port-ocean 0.22.7__tar.gz → 0.22.9__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.

Files changed (194) hide show
  1. {port_ocean-0.22.7 → port_ocean-0.22.9}/PKG-INFO +1 -1
  2. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/authentication.py +2 -2
  3. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/client.py +4 -4
  4. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/mixins/blueprints.py +10 -10
  5. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/mixins/entities.py +27 -5
  6. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/mixins/integrations.py +8 -8
  7. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/mixins/migrations.py +2 -2
  8. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/mixins/organization.py +2 -2
  9. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/utils.py +9 -4
  10. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/entities_state_applier/port/applier.py +1 -1
  11. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/integrations/mixins/sync_raw.py +37 -12
  12. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/helpers/metric/metric.py +115 -9
  13. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/helpers/metric/utils.py +1 -1
  14. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/clients/port/mixins/test_organization_mixin.py +1 -0
  15. {port_ocean-0.22.7 → port_ocean-0.22.9}/pyproject.toml +1 -1
  16. {port_ocean-0.22.7 → port_ocean-0.22.9}/LICENSE.md +0 -0
  17. {port_ocean-0.22.7 → port_ocean-0.22.9}/README.md +0 -0
  18. {port_ocean-0.22.7 → port_ocean-0.22.9}/integrations/_infra/Dockerfile.Deb +0 -0
  19. {port_ocean-0.22.7 → port_ocean-0.22.9}/integrations/_infra/Dockerfile.alpine +0 -0
  20. {port_ocean-0.22.7 → port_ocean-0.22.9}/integrations/_infra/Dockerfile.base.builder +0 -0
  21. {port_ocean-0.22.7 → port_ocean-0.22.9}/integrations/_infra/Dockerfile.base.runner +0 -0
  22. {port_ocean-0.22.7 → port_ocean-0.22.9}/integrations/_infra/Dockerfile.dockerignore +0 -0
  23. {port_ocean-0.22.7 → port_ocean-0.22.9}/integrations/_infra/Makefile +0 -0
  24. {port_ocean-0.22.7 → port_ocean-0.22.9}/integrations/_infra/grpcio.sh +0 -0
  25. {port_ocean-0.22.7 → port_ocean-0.22.9}/integrations/_infra/init.sh +0 -0
  26. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/__init__.py +0 -0
  27. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/bootstrap.py +0 -0
  28. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/__init__.py +0 -0
  29. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cli.py +0 -0
  30. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/__init__.py +0 -0
  31. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/defaults/__init___.py +0 -0
  32. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/defaults/clean.py +0 -0
  33. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/defaults/dock.py +0 -0
  34. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/defaults/group.py +0 -0
  35. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/list_integrations.py +0 -0
  36. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/main.py +0 -0
  37. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/new.py +0 -0
  38. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/pull.py +0 -0
  39. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/sail.py +0 -0
  40. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/commands/version.py +0 -0
  41. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/__init__.py +0 -0
  42. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/cookiecutter.json +0 -0
  43. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/extensions.py +0 -0
  44. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/hooks/post_gen_project.py +0 -0
  45. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.env.example +0 -0
  46. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.gitignore +0 -0
  47. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/.gitignore +0 -0
  48. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/blueprints.json +0 -0
  49. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/resources/port-app-config.yml +0 -0
  50. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/.port/spec.yaml +0 -0
  51. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CHANGELOG.md +0 -0
  52. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/CONTRIBUTING.md +0 -0
  53. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/README.md +0 -0
  54. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/changelog/.gitignore +0 -0
  55. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/debug.py +0 -0
  56. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/main.py +0 -0
  57. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/poetry.toml +0 -0
  58. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/pyproject.toml +0 -0
  59. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/sonar-project.properties +0 -0
  60. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/__init__.py +0 -0
  61. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/cookiecutter/{{cookiecutter.integration_slug}}/tests/test_sample.py +0 -0
  62. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/cli/utils.py +0 -0
  63. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/__init__.py +0 -0
  64. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/auth/__init__.py +0 -0
  65. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/auth/auth_client.py +0 -0
  66. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/auth/oauth_client.py +0 -0
  67. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/__init__.py +0 -0
  68. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/mixins/__init__.py +0 -0
  69. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/retry_transport.py +0 -0
  70. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/clients/port/types.py +0 -0
  71. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/config/__init__.py +0 -0
  72. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/config/base.py +0 -0
  73. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/config/dynamic.py +0 -0
  74. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/config/settings.py +0 -0
  75. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/consumers/__init__.py +0 -0
  76. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/consumers/kafka_consumer.py +0 -0
  77. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/context/__init__.py +0 -0
  78. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/context/event.py +0 -0
  79. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/context/ocean.py +0 -0
  80. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/context/resource.py +0 -0
  81. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/__init__.py +0 -0
  82. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/defaults/__init__.py +0 -0
  83. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/defaults/clean.py +0 -0
  84. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/defaults/common.py +0 -0
  85. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/defaults/initialize.py +0 -0
  86. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/event_listener/__init__.py +0 -0
  87. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/event_listener/base.py +0 -0
  88. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/event_listener/factory.py +0 -0
  89. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/event_listener/http.py +0 -0
  90. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/event_listener/kafka.py +0 -0
  91. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/event_listener/once.py +0 -0
  92. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/event_listener/polling.py +0 -0
  93. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/event_listener/webhooks_only.py +0 -0
  94. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/__init__.py +0 -0
  95. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/base.py +0 -0
  96. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/entities_state_applier/__init__.py +0 -0
  97. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/entities_state_applier/base.py +0 -0
  98. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/entities_state_applier/port/__init__.py +0 -0
  99. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/entities_state_applier/port/get_related_entities.py +0 -0
  100. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/entities_state_applier/port/order_by_entities_dependencies.py +0 -0
  101. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/entity_processor/__init__.py +0 -0
  102. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/entity_processor/base.py +0 -0
  103. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/entity_processor/jq_entity_processor.py +0 -0
  104. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/port_app_config/__init__.py +0 -0
  105. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/port_app_config/api.py +0 -0
  106. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/port_app_config/base.py +0 -0
  107. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/port_app_config/models.py +0 -0
  108. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/queue/__init__.py +0 -0
  109. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/queue/abstract_queue.py +0 -0
  110. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/queue/local_queue.py +0 -0
  111. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/resync_state_updater/__init__.py +0 -0
  112. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/resync_state_updater/updater.py +0 -0
  113. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/webhook/__init__.py +0 -0
  114. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/webhook/abstract_webhook_processor.py +0 -0
  115. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/webhook/processor_manager.py +0 -0
  116. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/handlers/webhook/webhook_event.py +0 -0
  117. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/integrations/__init__.py +0 -0
  118. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/integrations/base.py +0 -0
  119. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/integrations/mixins/__init__.py +0 -0
  120. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/integrations/mixins/events.py +0 -0
  121. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/integrations/mixins/handler.py +0 -0
  122. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/integrations/mixins/live_events.py +0 -0
  123. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/integrations/mixins/sync.py +0 -0
  124. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/integrations/mixins/utils.py +0 -0
  125. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/models.py +0 -0
  126. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/ocean_types.py +0 -0
  127. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/utils/entity_topological_sorter.py +0 -0
  128. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/core/utils/utils.py +0 -0
  129. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/debug_cli.py +0 -0
  130. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/exceptions/__init__.py +0 -0
  131. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/exceptions/api.py +0 -0
  132. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/exceptions/base.py +0 -0
  133. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/exceptions/clients.py +0 -0
  134. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/exceptions/context.py +0 -0
  135. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/exceptions/core.py +0 -0
  136. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/exceptions/port_defaults.py +0 -0
  137. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/exceptions/utils.py +0 -0
  138. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/exceptions/webhook_processor.py +0 -0
  139. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/helpers/__init__.py +0 -0
  140. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/helpers/async_client.py +0 -0
  141. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/helpers/retry.py +0 -0
  142. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/log/__init__.py +0 -0
  143. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/log/handlers.py +0 -0
  144. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/log/logger_setup.py +0 -0
  145. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/log/sensetive.py +0 -0
  146. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/middlewares.py +0 -0
  147. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/ocean.py +0 -0
  148. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/py.typed +0 -0
  149. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/run.py +0 -0
  150. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/sonar-project.properties +0 -0
  151. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/__init__.py +0 -0
  152. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/clients/__init__.py +0 -0
  153. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/clients/oauth/__init__.py +0 -0
  154. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/clients/oauth/test_oauth_client.py +0 -0
  155. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/clients/port/mixins/test_entities.py +0 -0
  156. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/conftest.py +0 -0
  157. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/conftest.py +0 -0
  158. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/defaults/test_common.py +0 -0
  159. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/entities_state_applier/test_applier.py +0 -0
  160. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/entity_processor/test_jq_entity_processor.py +0 -0
  161. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/mixins/test_live_events.py +0 -0
  162. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/mixins/test_sync_raw.py +0 -0
  163. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/port_app_config/test_api.py +0 -0
  164. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/port_app_config/test_base.py +0 -0
  165. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/queue/test_local_queue.py +0 -0
  166. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/webhook/test_abstract_webhook_processor.py +0 -0
  167. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/webhook/test_processor_manager.py +0 -0
  168. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/handlers/webhook/test_webhook_event.py +0 -0
  169. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/test_utils.py +0 -0
  170. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/utils/test_entity_topological_sorter.py +0 -0
  171. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/core/utils/test_resolve_entities_diff.py +0 -0
  172. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/helpers/__init__.py +0 -0
  173. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/helpers/fake_port_api.py +0 -0
  174. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/helpers/fixtures.py +0 -0
  175. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/helpers/integration.py +0 -0
  176. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/helpers/ocean_app.py +0 -0
  177. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/helpers/port_client.py +0 -0
  178. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/helpers/smoke_test.py +0 -0
  179. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/log/test_handlers.py +0 -0
  180. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/test_metric.py +0 -0
  181. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/test_ocean.py +0 -0
  182. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/test_smoke.py +0 -0
  183. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/utils/test_async_iterators.py +0 -0
  184. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/tests/utils/test_cache.py +0 -0
  185. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/utils/__init__.py +0 -0
  186. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/utils/async_http.py +0 -0
  187. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/utils/async_iterators.py +0 -0
  188. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/utils/cache.py +0 -0
  189. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/utils/misc.py +0 -0
  190. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/utils/queue_utils.py +0 -0
  191. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/utils/repeat.py +0 -0
  192. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/utils/signal.py +0 -0
  193. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/utils/time.py +0 -0
  194. {port_ocean-0.22.7 → port_ocean-0.22.9}/port_ocean/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: port-ocean
3
- Version: 0.22.7
3
+ Version: 0.22.9
4
4
  Summary: Port Ocean is a CLI tool for managing your Port projects.
5
5
  Home-page: https://app.getport.io
6
6
  Keywords: ocean,port-ocean,port
@@ -6,7 +6,7 @@ from loguru import logger
6
6
  from pydantic import BaseModel, Field, PrivateAttr
7
7
 
8
8
  from port_ocean.clients.port.types import UserAgentType
9
- from port_ocean.clients.port.utils import handle_status_code
9
+ from port_ocean.clients.port.utils import handle_port_status_code
10
10
  from port_ocean.utils.misc import get_time
11
11
 
12
12
 
@@ -58,7 +58,7 @@ class PortAuthentication:
58
58
  json=credentials,
59
59
  extensions={"retryable": True},
60
60
  )
61
- handle_status_code(response)
61
+ handle_port_status_code(response)
62
62
  return TokenResponse(**response.json())
63
63
 
64
64
  def user_agent(self, user_agent_type: UserAgentType | None = None) -> str:
@@ -10,7 +10,7 @@ from port_ocean.clients.port.types import (
10
10
  KafkaCreds,
11
11
  )
12
12
  from port_ocean.clients.port.utils import (
13
- handle_status_code,
13
+ handle_port_status_code,
14
14
  get_internal_http_client,
15
15
  )
16
16
  from port_ocean.exceptions.clients import KafkaCredentialsNotFound
@@ -59,7 +59,7 @@ class PortClient(
59
59
  )
60
60
  if response.is_error:
61
61
  logger.error("Error getting kafka credentials")
62
- handle_status_code(response)
62
+ handle_port_status_code(response)
63
63
 
64
64
  credentials = response.json().get("credentials")
65
65
 
@@ -76,7 +76,7 @@ class PortClient(
76
76
  )
77
77
  if response.is_error:
78
78
  logger.error(f"Error getting organization id, error: {response.text}")
79
- handle_status_code(response)
79
+ handle_port_status_code(response)
80
80
 
81
81
  return response.json()["organization"]["id"]
82
82
 
@@ -90,7 +90,7 @@ class PortClient(
90
90
  headers=await self.auth.headers(),
91
91
  json=state,
92
92
  )
93
- handle_status_code(response, should_raise, should_log)
93
+ handle_port_status_code(response, should_raise, should_log)
94
94
  if response.is_success and should_log:
95
95
  logger.info("Integration resync state updated successfully")
96
96
 
@@ -5,7 +5,7 @@ from loguru import logger
5
5
 
6
6
  from port_ocean.clients.port.authentication import PortAuthentication
7
7
  from port_ocean.clients.port.types import UserAgentType
8
- from port_ocean.clients.port.utils import handle_status_code
8
+ from port_ocean.clients.port.utils import handle_port_status_code
9
9
  from port_ocean.core.models import Blueprint
10
10
 
11
11
 
@@ -22,7 +22,7 @@ class BlueprintClientMixin:
22
22
  f"{self.auth.api_url}/blueprints/{identifier}",
23
23
  headers=await self.auth.headers(),
24
24
  )
25
- handle_status_code(response, should_log=should_log)
25
+ handle_port_status_code(response, should_log=should_log)
26
26
  return Blueprint.parse_obj(response.json()["blueprint"])
27
27
 
28
28
  async def create_blueprint(
@@ -35,7 +35,7 @@ class BlueprintClientMixin:
35
35
  response = await self.client.post(
36
36
  f"{self.auth.api_url}/blueprints", headers=headers, json=raw_blueprint
37
37
  )
38
- handle_status_code(response)
38
+ handle_port_status_code(response)
39
39
  return response.json()["blueprint"]
40
40
 
41
41
  async def patch_blueprint(
@@ -51,7 +51,7 @@ class BlueprintClientMixin:
51
51
  headers=headers,
52
52
  json=raw_blueprint,
53
53
  )
54
- handle_status_code(response)
54
+ handle_port_status_code(response)
55
55
 
56
56
  async def delete_blueprint(
57
57
  self,
@@ -70,7 +70,7 @@ class BlueprintClientMixin:
70
70
  f"{self.auth.api_url}/blueprints/{identifier}",
71
71
  headers=headers,
72
72
  )
73
- handle_status_code(response, should_raise)
73
+ handle_port_status_code(response, should_raise)
74
74
  return None
75
75
  else:
76
76
  response = await self.client.delete(
@@ -78,7 +78,7 @@ class BlueprintClientMixin:
78
78
  headers=await self.auth.headers(),
79
79
  )
80
80
 
81
- handle_status_code(response, should_raise)
81
+ handle_port_status_code(response, should_raise)
82
82
  return response.json().get("migrationId", "")
83
83
 
84
84
  async def create_action(
@@ -91,7 +91,7 @@ class BlueprintClientMixin:
91
91
  headers=await self.auth.headers(),
92
92
  )
93
93
 
94
- handle_status_code(response, should_log=should_log)
94
+ handle_port_status_code(response, should_log=should_log)
95
95
 
96
96
  async def create_scorecard(
97
97
  self,
@@ -106,7 +106,7 @@ class BlueprintClientMixin:
106
106
  headers=await self.auth.headers(),
107
107
  )
108
108
 
109
- handle_status_code(response, should_log=should_log)
109
+ handle_port_status_code(response, should_log=should_log)
110
110
 
111
111
  async def create_page(
112
112
  self, page: dict[str, Any], should_log: bool = True
@@ -118,7 +118,7 @@ class BlueprintClientMixin:
118
118
  headers=await self.auth.headers(),
119
119
  )
120
120
 
121
- handle_status_code(response, should_log=should_log)
121
+ handle_port_status_code(response, should_log=should_log)
122
122
  return page
123
123
 
124
124
  async def delete_page(
@@ -132,4 +132,4 @@ class BlueprintClientMixin:
132
132
  headers=await self.auth.headers(),
133
133
  )
134
134
 
135
- handle_status_code(response, should_raise)
135
+ handle_port_status_code(response, should_raise)
@@ -5,16 +5,18 @@ from urllib.parse import quote_plus
5
5
 
6
6
  import httpx
7
7
  from loguru import logger
8
-
8
+ from port_ocean.context.ocean import ocean
9
9
  from port_ocean.clients.port.authentication import PortAuthentication
10
10
  from port_ocean.clients.port.types import RequestOptions, UserAgentType
11
11
  from port_ocean.clients.port.utils import (
12
- handle_status_code,
12
+ handle_port_status_code,
13
13
  PORT_HTTP_MAX_CONNECTIONS_LIMIT,
14
14
  )
15
15
  from port_ocean.core.models import Entity, PortAPIErrorMessage
16
16
  from starlette import status
17
17
 
18
+ from port_ocean.helpers.metric.metric import MetricPhase, MetricType
19
+
18
20
 
19
21
  class EntityClientMixin:
20
22
  def __init__(self, auth: PortAuthentication, client: httpx.AsyncClient):
@@ -81,6 +83,15 @@ class EntityClientMixin:
81
83
  f"blueprint: {entity.blueprint}"
82
84
  )
83
85
  result = response.json()
86
+ ocean.metrics.inc_metric(
87
+ name=MetricType.OBJECT_COUNT_NAME,
88
+ labels=[
89
+ ocean.metrics.current_resource_kind(),
90
+ MetricPhase.LOAD,
91
+ MetricPhase.LoadResult.FAILED,
92
+ ],
93
+ value=1,
94
+ )
84
95
 
85
96
  if (
86
97
  response.status_code == status.HTTP_404_NOT_FOUND
@@ -89,7 +100,18 @@ class EntityClientMixin:
89
100
  ):
90
101
  # Return false to differentiate from `result_entity.is_using_search_identifier`
91
102
  return False
92
- handle_status_code(response, should_raise)
103
+ else:
104
+ ocean.metrics.inc_metric(
105
+ name=MetricType.OBJECT_COUNT_NAME,
106
+ labels=[
107
+ ocean.metrics.current_resource_kind(),
108
+ MetricPhase.LOAD,
109
+ MetricPhase.LoadResult.LOADED,
110
+ ],
111
+ value=1,
112
+ )
113
+
114
+ handle_port_status_code(response, should_raise)
93
115
  result = response.json()
94
116
 
95
117
  result_entity = (
@@ -192,7 +214,7 @@ class EntityClientMixin:
192
214
  f"blueprint: {entity.blueprint}"
193
215
  )
194
216
 
195
- handle_status_code(response, should_raise)
217
+ handle_port_status_code(response, should_raise)
196
218
 
197
219
  async def batch_delete_entities(
198
220
  self,
@@ -252,7 +274,7 @@ class EntityClientMixin:
252
274
  },
253
275
  extensions={"retryable": True},
254
276
  )
255
- handle_status_code(response)
277
+ handle_port_status_code(response)
256
278
  return [Entity.parse_obj(result) for result in response.json()["entities"]]
257
279
 
258
280
  async def search_batch_entities(
@@ -5,7 +5,7 @@ from urllib.parse import quote_plus
5
5
  import httpx
6
6
  from loguru import logger
7
7
  from port_ocean.clients.port.authentication import PortAuthentication
8
- from port_ocean.clients.port.utils import handle_status_code
8
+ from port_ocean.clients.port.utils import handle_port_status_code
9
9
  from port_ocean.exceptions.port_defaults import DefaultsProvisionFailed
10
10
  from port_ocean.log.sensetive import sensitive_log_filter
11
11
 
@@ -56,7 +56,7 @@ class IntegrationClientMixin:
56
56
  headers=await self.auth.headers(),
57
57
  )
58
58
 
59
- handle_status_code(response, should_raise, should_log)
59
+ handle_port_status_code(response, should_raise, should_log)
60
60
 
61
61
  return response.json().get("integrations", [])
62
62
 
@@ -75,7 +75,7 @@ class IntegrationClientMixin:
75
75
  has_provision_feature_flag: bool = False,
76
76
  ) -> dict[str, Any]:
77
77
  response = await self._get_current_integration()
78
- handle_status_code(response, should_raise, should_log)
78
+ handle_port_status_code(response, should_raise, should_log)
79
79
  integration = response.json().get("integration", {})
80
80
  if integration.get("config", None) or not integration:
81
81
  return integration
@@ -164,7 +164,7 @@ class IntegrationClientMixin:
164
164
  json=json,
165
165
  params=query_params,
166
166
  )
167
- handle_status_code(response)
167
+ handle_port_status_code(response)
168
168
  if create_port_resources_origin_in_port:
169
169
  result = (
170
170
  await self._poll_integration_until_default_provisioning_is_complete()
@@ -194,7 +194,7 @@ class IntegrationClientMixin:
194
194
  headers=headers,
195
195
  json=json,
196
196
  )
197
- handle_status_code(response)
197
+ handle_port_status_code(response)
198
198
  return response.json()["integration"]
199
199
 
200
200
  async def ingest_integration_logs(self, logs: list[dict[str, Any]]) -> None:
@@ -208,7 +208,7 @@ class IntegrationClientMixin:
208
208
  "logs": logs,
209
209
  },
210
210
  )
211
- handle_status_code(response, should_log=False)
211
+ handle_port_status_code(response, should_log=False)
212
212
  logger.debug("Logs successfully ingested")
213
213
 
214
214
  async def ingest_integration_kind_examples(
@@ -223,7 +223,7 @@ class IntegrationClientMixin:
223
223
  "examples": sensitive_log_filter.mask_object(data, full_hide=True),
224
224
  },
225
225
  )
226
- handle_status_code(response, should_log=should_log)
226
+ handle_port_status_code(response, should_log=should_log)
227
227
  logger.debug(f"Examples for kind {kind} successfully ingested")
228
228
 
229
229
  async def _delete_current_integration(self) -> httpx.Response:
@@ -238,5 +238,5 @@ class IntegrationClientMixin:
238
238
  self, should_raise: bool = True, should_log: bool = True
239
239
  ) -> dict[str, Any]:
240
240
  response = await self._delete_current_integration()
241
- handle_status_code(response, should_raise, should_log)
241
+ handle_port_status_code(response, should_raise, should_log)
242
242
  return response.json()
@@ -4,7 +4,7 @@ import httpx
4
4
  from loguru import logger
5
5
 
6
6
  from port_ocean.clients.port.authentication import PortAuthentication
7
- from port_ocean.clients.port.utils import handle_status_code
7
+ from port_ocean.clients.port.utils import handle_port_status_code
8
8
  from port_ocean.core.models import Migration
9
9
 
10
10
 
@@ -28,7 +28,7 @@ class MigrationClientMixin:
28
28
  headers=headers,
29
29
  )
30
30
 
31
- handle_status_code(response, should_raise=True)
31
+ handle_port_status_code(response, should_raise=True)
32
32
 
33
33
  migration_status = response.json().get("migration", {}).get("status", None)
34
34
  if (
@@ -2,7 +2,7 @@ from typing import List
2
2
  import httpx
3
3
  from loguru import logger
4
4
  from port_ocean.clients.port.authentication import PortAuthentication
5
- from port_ocean.clients.port.utils import handle_status_code
5
+ from port_ocean.clients.port.utils import handle_port_status_code
6
6
 
7
7
 
8
8
  class OrganizationClientMixin:
@@ -27,5 +27,5 @@ class OrganizationClientMixin:
27
27
  self, should_raise: bool = True, should_log: bool = True
28
28
  ) -> List[str]:
29
29
  response = await self._get_organization_feature_flags()
30
- handle_status_code(response, should_raise, should_log)
30
+ handle_port_status_code(response, should_raise, should_log)
31
31
  return response.json().get("organization", {}).get("featureFlags", [])
@@ -62,12 +62,17 @@ def get_internal_http_client(port_client: "PortClient") -> httpx.AsyncClient:
62
62
  return _port_internal_async_client
63
63
 
64
64
 
65
- def handle_status_code(
65
+ def handle_port_status_code(
66
66
  response: httpx.Response, should_raise: bool = True, should_log: bool = True
67
67
  ) -> None:
68
68
  if should_log and response.is_error:
69
- logger.error(
70
- f"Request failed with status code: {response.status_code}, Error: {response.text}"
71
- )
69
+ error_message = f"Request failed with status code: {response.status_code}, Error: {response.text}"
70
+ if response.status_code >= 500 and response.headers.get("x-trace-id"):
71
+ logger.error(
72
+ error_message,
73
+ trace_id=response.headers.get("x-trace-id"),
74
+ )
75
+ else:
76
+ logger.error(error_message)
72
77
  if should_raise:
73
78
  response.raise_for_status()
@@ -103,7 +103,7 @@ class HttpEntitiesStateApplier(BaseEntitiesStateApplier):
103
103
  and deletion_rate <= entity_deletion_threshold
104
104
  ):
105
105
  await self._safe_delete(diff.deleted, kept_entities, user_agent_type)
106
- ocean.metrics.set_metric(
106
+ ocean.metrics.inc_metric(
107
107
  name=MetricType.DELETION_COUNT_NAME,
108
108
  labels=[ocean.metrics.current_resource_kind(), MetricPhase.DELETE],
109
109
  value=len(diff.deleted),
@@ -31,7 +31,7 @@ from port_ocean.core.ocean_types import (
31
31
  )
32
32
  from port_ocean.core.utils.utils import resolve_entities_diff, zip_and_sum, gather_and_split_errors_from_results
33
33
  from port_ocean.exceptions.core import OceanAbortException
34
- from port_ocean.helpers.metric.metric import MetricType, MetricPhase
34
+ from port_ocean.helpers.metric.metric import SyncState, MetricType, MetricPhase
35
35
  from port_ocean.helpers.metric.utils import TimeMetric
36
36
 
37
37
  SEND_RAW_DATA_EXAMPLES_AMOUNT = 5
@@ -238,11 +238,21 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
238
238
  if changed_entities:
239
239
  logger.info("Upserting changed entities", changed_entities=len(changed_entities),
240
240
  total_entities=len(objects_diff[0].entity_selector_diff.passed))
241
+ ocean.metrics.inc_metric(
242
+ name=MetricType.OBJECT_COUNT_NAME,
243
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.SKIPPED],
244
+ value=len(objects_diff[0].entity_selector_diff.passed) - len(changed_entities)
245
+ )
241
246
  await self.entities_state_applier.upsert(
242
247
  changed_entities, user_agent_type
243
248
  )
244
249
  else:
245
250
  logger.info("Entities in batch didn't changed since last sync, skipping", total_entities=len(objects_diff[0].entity_selector_diff.passed))
251
+ ocean.metrics.inc_metric(
252
+ name=MetricType.OBJECT_COUNT_NAME,
253
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD, MetricPhase.LoadResult.SKIPPED],
254
+ value=len(objects_diff[0].entity_selector_diff.passed)
255
+ )
246
256
  modified_objects = [ocean.port_client._reduce_entity(entity) for entity in objects_diff[0].entity_selector_diff.passed]
247
257
  except Exception as e:
248
258
  logger.warning(f"Failed to resolve batch entities with Port, falling back to upserting all entities: {str(e)}")
@@ -335,6 +345,7 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
335
345
  passed_entities.extend(calculation_result.entity_selector_diff.passed)
336
346
  number_of_transformed_entities += calculation_result.number_of_transformed_entities
337
347
  except* OceanAbortException as error:
348
+ ocean.metrics.sync_state = SyncState.FAILED
338
349
  errors.append(error)
339
350
 
340
351
  logger.info(
@@ -347,18 +358,30 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
347
358
  value=int(not errors)
348
359
  )
349
360
 
350
- ocean.metrics.set_metric(
361
+ ocean.metrics.inc_metric(
351
362
  name=MetricType.OBJECT_COUNT_NAME,
352
- labels=[ocean.metrics.current_resource_kind(), MetricPhase.EXTRACT],
363
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.EXTRACT , MetricPhase.ExtractResult.EXTRACTED],
353
364
  value=number_of_raw_results
354
365
  )
355
366
 
356
- ocean.metrics.set_metric(
367
+ ocean.metrics.inc_metric(
357
368
  name=MetricType.OBJECT_COUNT_NAME,
358
- labels=[ocean.metrics.current_resource_kind(), MetricPhase.TRANSFORM],
369
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.TRANSFORM , MetricPhase.TransformResult.TRANSFORMED],
359
370
  value=number_of_transformed_entities
360
371
  )
361
372
 
373
+ ocean.metrics.inc_metric(
374
+ name=MetricType.OBJECT_COUNT_NAME,
375
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.TRANSFORM , MetricPhase.TransformResult.FILTERED_OUT],
376
+ value=number_of_raw_results -number_of_transformed_entities
377
+ )
378
+
379
+ ocean.metrics.inc_metric(
380
+ name=MetricType.OBJECT_COUNT_NAME,
381
+ labels=[ocean.metrics.current_resource_kind(), MetricPhase.TRANSFORM , MetricPhase.TransformResult.FAILED],
382
+ value=len(errors)
383
+ )
384
+
362
385
  return passed_entities, errors
363
386
 
364
387
  async def register_raw(
@@ -558,7 +581,6 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
558
581
  for entity in event.entity_topological_sorter.get_entities(False):
559
582
  await self.entities_state_applier.context.port_client.upsert_entity(entity,event.port_app_config.get_port_request_options(),user_agent_type,should_raise=False)
560
583
 
561
-
562
584
  @TimeMetric(MetricPhase.RESYNC)
563
585
  async def sync_raw_all(
564
586
  self,
@@ -584,12 +606,16 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
584
606
  EventType.RESYNC,
585
607
  trigger_type=trigger_type,
586
608
  ):
609
+ ocean.metrics.event_id = event.id
610
+
587
611
  # If a resync is triggered due to a mappings change, we want to make sure that we have the updated version
588
612
  # rather than the old cache
589
613
  app_config = await self.port_app_config_handler.get_port_app_config(
590
614
  use_cache=False
591
615
  )
592
616
  logger.info(f"Resync will use the following mappings: {app_config.dict()}")
617
+ ocean.metrics.initialize_metrics([f"{resource.kind}-{index}" for index, resource in enumerate(app_config.resources)])
618
+ await ocean.metrics.flush()
593
619
 
594
620
  # Execute resync_start hooks
595
621
  for resync_start_fn in self.event_strategy["resync_start"]:
@@ -616,20 +642,19 @@ class SyncRawMixin(HandlerMixin, EventsMixin):
616
642
  # config as we might have multiple resources in the same event
617
643
  async with resource_context(resource,index):
618
644
  resource_kind_id = f"{resource.kind}-{index}"
645
+ ocean.metrics.sync_state = SyncState.SYNCING
646
+ await ocean.metrics.flush(kind=resource_kind_id)
647
+
619
648
  task = asyncio.create_task(
620
649
  self._register_in_batches(resource, user_agent_type)
621
650
  )
622
651
 
623
652
  event.on_abort(lambda: task.cancel())
624
653
  kind_results: tuple[list[Entity], list[Exception]] = await task
625
- ocean.metrics.set_metric(
626
- name=MetricType.OBJECT_COUNT_NAME,
627
- labels=[ocean.metrics.current_resource_kind(), MetricPhase.LOAD],
628
- value=len(kind_results[0])
629
- )
630
654
 
631
655
  creation_results.append(kind_results)
632
-
656
+ if ocean.metrics.sync_state != SyncState.FAILED:
657
+ ocean.metrics.sync_state = SyncState.COMPLETED
633
658
  await ocean.metrics.flush(kind=resource_kind_id)
634
659
 
635
660
  await self.sort_and_upsert_failed_entities(user_agent_type)
@@ -22,6 +22,19 @@ class MetricPhase:
22
22
  RESYNC = "resync"
23
23
  DELETE = "delete"
24
24
 
25
+ class TransformResult:
26
+ TRANSFORMED = "transformed"
27
+ FILTERED_OUT = "filtered_out"
28
+ FAILED = "failed"
29
+
30
+ class LoadResult:
31
+ LOADED = "loaded"
32
+ FAILED = "failed"
33
+ SKIPPED = "skipped"
34
+
35
+ class ExtractResult:
36
+ EXTRACTED = "raw_extracted"
37
+
25
38
 
26
39
  class MetricType:
27
40
  # Define metric names as constants
@@ -33,6 +46,13 @@ class MetricType:
33
46
  DELETION_COUNT_NAME = "deletion_count"
34
47
 
35
48
 
49
+ class SyncState:
50
+ SYNCING = "syncing"
51
+ COMPLETED = "completed"
52
+ QUEUED = "queued"
53
+ FAILED = "failed"
54
+
55
+
36
56
  # Registry for core and custom metrics
37
57
  _metrics_registry: Dict[str, Tuple[str, str, List[str]]] = {
38
58
  MetricType.DURATION_NAME: (
@@ -43,7 +63,7 @@ _metrics_registry: Dict[str, Tuple[str, str, List[str]]] = {
43
63
  MetricType.OBJECT_COUNT_NAME: (
44
64
  MetricType.OBJECT_COUNT_NAME,
45
65
  "object_count description",
46
- ["kind", "phase"],
66
+ ["kind", "phase", "object_count_type"],
47
67
  ),
48
68
  MetricType.ERROR_COUNT_NAME: (
49
69
  MetricType.ERROR_COUNT_NAME,
@@ -86,6 +106,9 @@ class EmptyMetric:
86
106
  def labels(self, *args: Any) -> None:
87
107
  return None
88
108
 
109
+ def inc(self, *args: Any) -> None:
110
+ return None
111
+
89
112
 
90
113
  class Metrics:
91
114
  def __init__(
@@ -100,6 +123,24 @@ class Metrics:
100
123
  self.load_metrics()
101
124
  self._integration_version: Optional[str] = None
102
125
  self._ocean_version: Optional[str] = None
126
+ self.event_id = ""
127
+ self.sync_state = SyncState.QUEUED
128
+
129
+ @property
130
+ def event_id(self) -> str:
131
+ return self._event_id
132
+
133
+ @event_id.setter
134
+ def event_id(self, value: str) -> None:
135
+ self._event_id = value
136
+
137
+ @property
138
+ def sync_state(self) -> str:
139
+ return self._sync_state
140
+
141
+ @sync_state.setter
142
+ def sync_state(self, value: str) -> None:
143
+ self._sync_state = value
103
144
 
104
145
  @property
105
146
  def integration_version(self) -> str:
@@ -139,6 +180,19 @@ class Metrics:
139
180
  return EmptyMetric()
140
181
  return metrics.labels(*labels)
141
182
 
183
+ def inc_metric(self, name: str, labels: list[str], value: float) -> None:
184
+ """Increment a metric value in a single method call.
185
+
186
+ Args:
187
+ name (str): The metric name to inc.
188
+ labels (list[str]): The labels to apply to the metric.
189
+ value (float): The value to inc.
190
+ """
191
+ if not self.enabled:
192
+ return None
193
+
194
+ self.get_metric(name, labels).inc(value)
195
+
142
196
  def set_metric(self, name: str, labels: list[str], value: float) -> None:
143
197
  """Set a metric value in a single method call.
144
198
 
@@ -152,6 +206,49 @@ class Metrics:
152
206
 
153
207
  self.get_metric(name, labels).set(value)
154
208
 
209
+ def initialize_metrics(self, kind_blockes: list[str]) -> None:
210
+ for kind in kind_blockes:
211
+ self.set_metric(MetricType.SUCCESS_NAME, [kind, MetricPhase.RESYNC], 0)
212
+ self.set_metric(MetricType.DURATION_NAME, [kind, MetricPhase.RESYNC], 0)
213
+
214
+ self.set_metric(
215
+ MetricType.OBJECT_COUNT_NAME,
216
+ [kind, MetricPhase.EXTRACT, MetricPhase.ExtractResult.EXTRACTED],
217
+ 0,
218
+ )
219
+
220
+ self.set_metric(
221
+ MetricType.OBJECT_COUNT_NAME,
222
+ [kind, MetricPhase.TRANSFORM, MetricPhase.TransformResult.TRANSFORMED],
223
+ 0,
224
+ )
225
+ self.set_metric(
226
+ MetricType.OBJECT_COUNT_NAME,
227
+ [kind, MetricPhase.TRANSFORM, MetricPhase.TransformResult.FILTERED_OUT],
228
+ 0,
229
+ )
230
+ self.set_metric(
231
+ MetricType.OBJECT_COUNT_NAME,
232
+ [kind, MetricPhase.TRANSFORM, MetricPhase.TransformResult.FAILED],
233
+ 0,
234
+ )
235
+
236
+ self.set_metric(
237
+ MetricType.OBJECT_COUNT_NAME,
238
+ [kind, MetricPhase.LOAD, MetricPhase.LoadResult.LOADED],
239
+ 0,
240
+ )
241
+ self.set_metric(
242
+ MetricType.OBJECT_COUNT_NAME,
243
+ [kind, MetricPhase.LOAD, MetricPhase.LoadResult.FAILED],
244
+ 0,
245
+ )
246
+ self.set_metric(
247
+ MetricType.OBJECT_COUNT_NAME,
248
+ [kind, MetricPhase.LOAD, MetricPhase.LoadResult.SKIPPED],
249
+ 0,
250
+ )
251
+
155
252
  def create_mertic_router(self) -> APIRouter:
156
253
  if not self.enabled:
157
254
  return APIRouter()
@@ -201,14 +298,21 @@ class Metrics:
201
298
  if kind and sample.labels.get("kind") != kind:
202
299
  continue
203
300
 
204
- # Create nested dictionary structure based on labels
205
- for key, value in sample.labels.items():
206
- if key not in current_level:
207
- current_level[key] = {}
208
- current_level = current_level[key]
209
- if value not in current_level:
210
- current_level[value] = {}
211
- current_level = current_level[value]
301
+ # Get the ordered labels from the registry
302
+ ordered_labels = _metrics_registry.get(
303
+ sample.name, (None, None, [])
304
+ )[2]
305
+
306
+ # Create nested dictionary structure based on ordered labels
307
+ for label_name in ordered_labels:
308
+ if label_name in sample.labels:
309
+ value = sample.labels[label_name]
310
+ if label_name not in current_level:
311
+ current_level[label_name] = {}
312
+ current_level = current_level[label_name]
313
+ if value not in current_level:
314
+ current_level[value] = {}
315
+ current_level = current_level[value]
212
316
 
213
317
  current_level[sample.name] = sample.value
214
318
 
@@ -228,6 +332,8 @@ class Metrics:
228
332
  "ocean_version": self.ocean_version,
229
333
  "kind_identifier": kind_key,
230
334
  "kind": "-".join(kind_key.split("-")[:-1]),
335
+ "event_id": self.event_id,
336
+ "sync_state": self.sync_state,
231
337
  "metrics": metrics,
232
338
  }
233
339
  logger.info(f"Sending metrics to webhook {kind_key}: {event}")
@@ -17,7 +17,7 @@ def TimeMetric(phase: str) -> Any:
17
17
  res = await func(*args, **kwargs)
18
18
  end = time.monotonic()
19
19
  duration = end - start
20
- ocean.metrics.set_metric(
20
+ ocean.metrics.inc_metric(
21
21
  name=MetricType.DURATION_NAME,
22
22
  labels=[ocean.metrics.current_resource_kind(), phase],
23
23
  value=duration,