omnata-plugin-runtime 0.8.0a187__py3-none-any.whl → 0.8.0a188__py3-none-any.whl

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.
@@ -36,6 +36,7 @@ from .omnata_plugin import (
36
36
  )
37
37
  from pydantic import TypeAdapter
38
38
  from .rate_limiting import ApiLimits, RateLimitState
39
+ from opentelemetry import trace
39
40
 
40
41
  IMPORT_DIRECTORY_NAME = "snowflake_import_directory"
41
42
 
@@ -50,46 +51,40 @@ class PluginEntrypoint:
50
51
  self, plugin_fqn: str, session: Session, module_name: str, class_name: str
51
52
  ):
52
53
  logger.info(f"Initialising plugin entrypoint for {plugin_fqn}")
53
- self._session = session
54
- import_dir = sys._xoptions[IMPORT_DIRECTORY_NAME]
55
- sys.path.append(os.path.join(import_dir, "app.zip"))
56
- module = importlib.import_module(module_name)
57
- class_obj = getattr(module, class_name)
58
- self._plugin_instance: OmnataPlugin = class_obj()
59
- self._plugin_instance._session = session # pylint: disable=protected-access
60
- # logging defaults
61
- snowflake_logger = logging.getLogger("snowflake")
62
- snowflake_logger.setLevel(logging.WARN) # we don't want snowflake queries being logged by default
63
- # the sync engine can tell the plugin to override log level via a session variable
64
- if session is not None:
65
- try:
66
- v = session.sql("select getvariable('LOG_LEVEL_OVERRIDES')").collect()
67
- result = v[0][0]
68
- if result is not None:
69
- log_level_overrides:Dict[str,str] = json.loads(result)
70
- for logger_name,level in log_level_overrides.items():
71
- logger_override = logging.getLogger(logger_name)
72
- logger_override.setLevel(level)
73
- logger_override.propagate = False
74
- for handler in logger_override.handlers:
75
- handler.setLevel(level)
76
- except Exception as e:
77
- logger.error(f"Error setting log level overrides: {str(e)}")
54
+ self.tracer = trace.get_tracer(__name__)
55
+ with self.tracer.start_as_current_span("plugin_initialization") as span:
56
+ self._session = session
57
+ import_dir = sys._xoptions[IMPORT_DIRECTORY_NAME]
58
+ span.add_event("Adding plugin zip to path")
59
+ sys.path.append(os.path.join(import_dir, "app.zip"))
60
+ span.add_event("Importing plugin module")
61
+ module = importlib.import_module(module_name)
62
+ class_obj = getattr(module, class_name)
63
+ self._plugin_instance: OmnataPlugin = class_obj()
64
+ self._plugin_instance._session = session # pylint: disable=protected-access
65
+ # logging defaults
66
+ snowflake_logger = logging.getLogger("snowflake")
67
+ snowflake_logger.setLevel(logging.WARN) # we don't want snowflake queries being logged by default
68
+ # the sync engine can tell the plugin to override log level via a session variable
69
+ if session is not None:
70
+ try:
71
+ span.add_event("Checking log level overrides")
72
+ v = session.sql("select getvariable('LOG_LEVEL_OVERRIDES')").collect()
73
+ result = v[0][0]
74
+ if result is not None:
75
+ log_level_overrides:Dict[str,str] = json.loads(result)
76
+ span.add_event("Applying log level overrides",log_level_overrides)
77
+ for logger_name,level in log_level_overrides.items():
78
+ logger_override = logging.getLogger(logger_name)
79
+ logger_override.setLevel(level)
80
+ logger_override.propagate = False
81
+ for handler in logger_override.handlers:
82
+ handler.setLevel(level)
83
+ except Exception as e:
84
+ logger.error(f"Error setting log level overrides: {str(e)}")
78
85
 
79
86
 
80
87
  def sync(self, sync_request: Dict):
81
- logger.info("Entered sync method")
82
- request = TypeAdapter(SyncRequestPayload).validate_python(sync_request)
83
- connection_secrets = get_secrets(
84
- request.oauth_secret_name, request.other_secrets_name
85
- )
86
- omnata_log_handler = OmnataPluginLogHandler(
87
- session=self._session,
88
- sync_id=request.sync_id,
89
- sync_branch_id=request.sync_branch_id,
90
- connection_id=request.connection_id,
91
- sync_run_id=request.run_id,
92
- )
93
88
  logger.add_extra('omnata.operation', 'sync')
94
89
  logger.add_extra('omnata.sync.id', request.sync_id)
95
90
  logger.add_extra('omnata.sync.direction', request.sync_direction)
@@ -97,50 +92,67 @@ class PluginEntrypoint:
97
92
  logger.add_extra('omnata.sync.run_id', request.run_id)
98
93
  logger.add_extra('omnata.sync_branch.id', request.sync_branch_id)
99
94
  logger.add_extra('omnata.sync_branch.name', request.sync_branch_name)
95
+ logger.info("Entered sync method")
96
+ with self.tracer.start_as_current_span("sync_initialization") as span:
97
+ span.add_event("Fetching secrets")
100
98
 
101
- omnata_log_handler.register(
102
- request.logging_level, self._plugin_instance.additional_loggers()
103
- )
104
- # construct some connection parameters for the purpose of getting the api limits
105
- connection_parameters = ConnectionConfigurationParameters(
106
- connection_method=request.connection_method,
107
- connectivity_option=request.connectivity_option,
108
- connection_parameters=request.connection_parameters,
109
- connection_secrets=connection_secrets
110
- )
111
- if request.oauth_secret_name is not None:
112
- connection_parameters.access_token_secret_name = request.oauth_secret_name
113
- all_api_limits = self._plugin_instance.api_limits(connection_parameters)
114
- logger.info(
115
- f"Default API limits: {json.dumps(to_jsonable_python(all_api_limits))}"
116
- )
117
- all_api_limits_by_category = {
118
- api_limit.endpoint_category: api_limit for api_limit in all_api_limits
119
- }
120
- all_api_limits_by_category.update(
121
- {
122
- k: v
123
- for k, v in [
124
- (x.endpoint_category, x) for x in request.api_limit_overrides
125
- ]
99
+ request = TypeAdapter(SyncRequestPayload).validate_python(sync_request)
100
+ connection_secrets = get_secrets(
101
+ request.oauth_secret_name, request.other_secrets_name
102
+ )
103
+ span.add_event("Configuring log handler")
104
+ omnata_log_handler = OmnataPluginLogHandler(
105
+ session=self._session,
106
+ sync_id=request.sync_id,
107
+ sync_branch_id=request.sync_branch_id,
108
+ connection_id=request.connection_id,
109
+ sync_run_id=request.run_id,
110
+ )
111
+
112
+ omnata_log_handler.register(
113
+ request.logging_level, self._plugin_instance.additional_loggers()
114
+ )
115
+ # construct some connection parameters for the purpose of getting the api limits
116
+ connection_parameters = ConnectionConfigurationParameters(
117
+ connection_method=request.connection_method,
118
+ connectivity_option=request.connectivity_option,
119
+ connection_parameters=request.connection_parameters,
120
+ connection_secrets=connection_secrets
121
+ )
122
+ if request.oauth_secret_name is not None:
123
+ connection_parameters.access_token_secret_name = request.oauth_secret_name
124
+ span.add_event("Configuring API Limits")
125
+ all_api_limits = self._plugin_instance.api_limits(connection_parameters)
126
+ logger.info(
127
+ f"Default API limits: {json.dumps(to_jsonable_python(all_api_limits))}"
128
+ )
129
+ all_api_limits_by_category = {
130
+ api_limit.endpoint_category: api_limit for api_limit in all_api_limits
126
131
  }
127
- )
128
- api_limits = list(all_api_limits_by_category.values())
129
- return_dict = {}
130
- logger.info(
131
- f"Rate limits state: {json.dumps(to_jsonable_python(request.rate_limits_state))}"
132
- )
133
- (rate_limit_state_all, rate_limit_state_this_branch) = RateLimitState.collapse(request.rate_limits_state,request.sync_id, request.sync_branch_name)
134
- # if any endpoint categories have no state, give them an empty state
135
- for api_limit in api_limits:
136
- if api_limit.endpoint_category not in rate_limit_state_all:
137
- rate_limit_state_all[api_limit.endpoint_category] = RateLimitState(
138
- wait_until=None, previous_request_timestamps=[]
139
- )
140
- if api_limit.endpoint_category not in rate_limit_state_this_branch:
141
- rate_limit_state_this_branch[api_limit.endpoint_category] = RateLimitState(
142
- wait_until=None, previous_request_timestamps=[]
143
- )
132
+ all_api_limits_by_category.update(
133
+ {
134
+ k: v
135
+ for k, v in [
136
+ (x.endpoint_category, x) for x in request.api_limit_overrides
137
+ ]
138
+ }
139
+ )
140
+ api_limits = list(all_api_limits_by_category.values())
141
+ return_dict = {}
142
+ logger.info(
143
+ f"Rate limits state: {json.dumps(to_jsonable_python(request.rate_limits_state))}"
144
+ )
145
+ (rate_limit_state_all, rate_limit_state_this_branch) = RateLimitState.collapse(request.rate_limits_state,request.sync_id, request.sync_branch_name)
146
+ # if any endpoint categories have no state, give them an empty state
147
+ for api_limit in api_limits:
148
+ if api_limit.endpoint_category not in rate_limit_state_all:
149
+ rate_limit_state_all[api_limit.endpoint_category] = RateLimitState(
150
+ wait_until=None, previous_request_timestamps=[]
151
+ )
152
+ if api_limit.endpoint_category not in rate_limit_state_this_branch:
153
+ rate_limit_state_this_branch[api_limit.endpoint_category] = RateLimitState(
154
+ wait_until=None, previous_request_timestamps=[]
155
+ )
144
156
 
145
157
  if request.sync_direction == "outbound":
146
158
  parameters = OutboundSyncConfigurationParameters(
@@ -174,11 +186,13 @@ class PluginEntrypoint:
174
186
  )
175
187
  try:
176
188
  self._plugin_instance._configuration_parameters = parameters
177
- with HttpRateLimiting(outbound_sync_request, parameters):
178
- self._plugin_instance.sync_outbound(parameters, outbound_sync_request)
189
+ with self.tracer.start_as_current_span("sync_execution") as span:
190
+ with HttpRateLimiting(outbound_sync_request, parameters):
191
+ self._plugin_instance.sync_outbound(parameters, outbound_sync_request)
179
192
  if self._plugin_instance.disable_background_workers is False:
180
- outbound_sync_request.apply_results_queue()
181
- outbound_sync_request.apply_rate_limit_state()
193
+ with self.tracer.start_as_current_span("results_finalization") as span:
194
+ outbound_sync_request.apply_results_queue()
195
+ outbound_sync_request.apply_rate_limit_state()
182
196
  if outbound_sync_request.deadline_reached:
183
197
  # if we actually hit the deadline, this is flagged by the cancellation checking worker and the cancellation
184
198
  # token is set. We throw it here as an error since that's currently how it flows back to the engine with a DELAYED state
@@ -232,19 +246,21 @@ class PluginEntrypoint:
232
246
  inbound_sync_request.update_activity("Invoking plugin")
233
247
  logger.info(f"inbound sync request: {inbound_sync_request}")
234
248
  # plugin_instance._inbound_sync_request = outbound_sync_request
235
- with HttpRateLimiting(inbound_sync_request, parameters):
236
- self._plugin_instance.sync_inbound(parameters, inbound_sync_request)
249
+ with self.tracer.start_as_current_span("sync_execution") as span:
250
+ with HttpRateLimiting(inbound_sync_request, parameters):
251
+ self._plugin_instance.sync_inbound(parameters, inbound_sync_request)
237
252
  logger.info("Finished invoking plugin")
238
253
  if self._plugin_instance.disable_background_workers is False:
239
- inbound_sync_request.update_activity("Staging remaining records")
240
- logger.info("Calling apply_results_queue")
241
- inbound_sync_request.apply_results_queue()
242
- try:
243
- # this is not critical, we wouldn't fail the sync over rate limit usage capture
244
- logger.info("Calling apply_rate_limit_state")
245
- inbound_sync_request.apply_rate_limit_state()
246
- except Exception as e:
247
- logger.error(f"Error applying rate limit state: {str(e)}")
254
+ with self.tracer.start_as_current_span("results_finalization") as span:
255
+ inbound_sync_request.update_activity("Staging remaining records")
256
+ logger.info("Calling apply_results_queue")
257
+ inbound_sync_request.apply_results_queue()
258
+ try:
259
+ # this is not critical, we wouldn't fail the sync over rate limit usage capture
260
+ logger.info("Calling apply_rate_limit_state")
261
+ inbound_sync_request.apply_rate_limit_state()
262
+ except Exception as e:
263
+ logger.error(f"Error applying rate limit state: {str(e)}")
248
264
  # here we used to do a final inbound_sync_request.apply_progress_updates(ignore_errors=False)
249
265
  # but it was erroring too much since there was usually a lot of DDL activity on the Snowflake side
250
266
  # so instead, we'll provide a final progress update via a return value from the proc
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: omnata-plugin-runtime
3
- Version: 0.8.0a187
3
+ Version: 0.8.0a188
4
4
  Summary: Classes and common runtime components for building and running Omnata Plugins
5
5
  Author: James Weakley
6
6
  Author-email: james.weakley@omnata.com
@@ -4,9 +4,9 @@ omnata_plugin_runtime/configuration.py,sha256=5M7dmQu9BO2msES9Foa8fOKfWui7iPSExA
4
4
  omnata_plugin_runtime/forms.py,sha256=ueodN2GIMS5N9fqebpY4uNGJnjEb9HcuaVQVfWH-cGg,19838
5
5
  omnata_plugin_runtime/logging.py,sha256=u_Bo2v4jS3C_2E_Y8a7yfZZcIP-h5Mak_FPnFHUwFbU,4378
6
6
  omnata_plugin_runtime/omnata_plugin.py,sha256=aggjb_CTTjhgqjS8CHPOm4ENU0jNcYoT6LC8yI1IeF4,130048
7
- omnata_plugin_runtime/plugin_entrypoints.py,sha256=LM4FHMW0N3N13oxsUqkSEbUhH95uFw-yNIJ5kNGDgWE,30633
7
+ omnata_plugin_runtime/plugin_entrypoints.py,sha256=z1NJpWvEj5TizCEU8YLnO5cWmeU8iSEsMK9CQaL47RA,32021
8
8
  omnata_plugin_runtime/rate_limiting.py,sha256=JKtyz8mA9D0FSZgQplPusmk2rVclcjkwtE59fQQrQ_I,25610
9
- omnata_plugin_runtime-0.8.0a187.dist-info/LICENSE,sha256=rGaMQG3R3F5-JGDp_-rlMKpDIkg5n0SI4kctTk8eZSI,56
10
- omnata_plugin_runtime-0.8.0a187.dist-info/METADATA,sha256=uVZoK32EmYnNrEAi7mDHt6x9iVZ2IvrBXWBqpmmbNeo,2148
11
- omnata_plugin_runtime-0.8.0a187.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
12
- omnata_plugin_runtime-0.8.0a187.dist-info/RECORD,,
9
+ omnata_plugin_runtime-0.8.0a188.dist-info/LICENSE,sha256=rGaMQG3R3F5-JGDp_-rlMKpDIkg5n0SI4kctTk8eZSI,56
10
+ omnata_plugin_runtime-0.8.0a188.dist-info/METADATA,sha256=OrGtX56IyJCjpFTsxkVu0IZI3Z9zJ5aHSzpgI0Mg3Bk,2148
11
+ omnata_plugin_runtime-0.8.0a188.dist-info/WHEEL,sha256=Nq82e9rUAnEjt98J6MlVmMCZb-t9cYE2Ir1kpBmnWfs,88
12
+ omnata_plugin_runtime-0.8.0a188.dist-info/RECORD,,