dagster-cloud 1.12.10__py3-none-any.whl → 1.12.12__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.
Files changed (37) hide show
  1. dagster_cloud/agent/dagster_cloud_agent.py +43 -86
  2. dagster_cloud/instance/__init__.py +1 -28
  3. dagster_cloud/pex/grpc/server/manager.py +3 -3
  4. dagster_cloud/version.py +1 -1
  5. dagster_cloud/workspace/docker/__init__.py +2 -1
  6. dagster_cloud/workspace/ecs/client.py +1 -1
  7. dagster_cloud/workspace/ecs/launcher.py +8 -4
  8. dagster_cloud/workspace/kubernetes/launcher.py +5 -3
  9. dagster_cloud/workspace/kubernetes/utils.py +6 -3
  10. dagster_cloud/workspace/user_code_launcher/user_code_launcher.py +41 -104
  11. dagster_cloud/workspace/user_code_launcher/utils.py +14 -0
  12. {dagster_cloud-1.12.10.dist-info → dagster_cloud-1.12.12.dist-info}/METADATA +16 -13
  13. {dagster_cloud-1.12.10.dist-info → dagster_cloud-1.12.12.dist-info}/RECORD +15 -37
  14. {dagster_cloud-1.12.10.dist-info → dagster_cloud-1.12.12.dist-info}/WHEEL +1 -1
  15. dagster_cloud/agent/instrumentation/__init__.py +0 -0
  16. dagster_cloud/agent/instrumentation/constants.py +0 -2
  17. dagster_cloud/agent/instrumentation/run_launch.py +0 -23
  18. dagster_cloud/agent/instrumentation/schedule.py +0 -34
  19. dagster_cloud/agent/instrumentation/sensor.py +0 -34
  20. dagster_cloud/opentelemetry/__init__.py +0 -0
  21. dagster_cloud/opentelemetry/config/__init__.py +0 -73
  22. dagster_cloud/opentelemetry/config/exporter.py +0 -81
  23. dagster_cloud/opentelemetry/config/log_record_processor.py +0 -40
  24. dagster_cloud/opentelemetry/config/logging_handler.py +0 -14
  25. dagster_cloud/opentelemetry/config/meter_provider.py +0 -9
  26. dagster_cloud/opentelemetry/config/metric_reader.py +0 -39
  27. dagster_cloud/opentelemetry/controller.py +0 -319
  28. dagster_cloud/opentelemetry/enum.py +0 -58
  29. dagster_cloud/opentelemetry/factories/__init__.py +0 -1
  30. dagster_cloud/opentelemetry/factories/logs.py +0 -113
  31. dagster_cloud/opentelemetry/factories/metrics.py +0 -121
  32. dagster_cloud/opentelemetry/metrics/__init__.py +0 -0
  33. dagster_cloud/opentelemetry/metrics/meter.py +0 -140
  34. dagster_cloud/opentelemetry/observers/__init__.py +0 -0
  35. dagster_cloud/opentelemetry/observers/dagster_exception_handler.py +0 -40
  36. dagster_cloud/opentelemetry/observers/execution_observer.py +0 -178
  37. {dagster_cloud-1.12.10.dist-info → dagster_cloud-1.12.12.dist-info}/top_level.txt +0 -0
@@ -1,140 +0,0 @@
1
- from collections.abc import Generator, Iterable, Sequence
2
- from typing import Callable, Optional, Union, cast
3
-
4
- # (Gauge is only exposed as a private class)
5
- from opentelemetry.metrics import (
6
- CallbackOptions,
7
- Counter,
8
- Histogram,
9
- Instrument,
10
- ObservableCounter,
11
- ObservableGauge,
12
- ObservableUpDownCounter,
13
- Observation,
14
- UpDownCounter,
15
- )
16
- from opentelemetry.metrics._internal import Meter as SDKMeter
17
-
18
- InstrumentKeyType = tuple[str, str, str]
19
- ObservableCallback = Callable[[CallbackOptions], Iterable[Observation]]
20
- ObservableGenerator = Generator[Iterable[Observation], CallbackOptions, None]
21
- ObserverType = Union[ObservableCallback, ObservableGenerator]
22
-
23
-
24
- class Meter:
25
- def __init__(self, meter: SDKMeter):
26
- self._meter = meter
27
- self._instruments: dict[InstrumentKeyType, Instrument] = {}
28
-
29
- @property
30
- def name(self) -> str:
31
- return self._meter.name
32
-
33
- @property
34
- def version(self) -> Optional[str]:
35
- return self._meter.version
36
-
37
- @property
38
- def schema_url(self) -> Optional[str]:
39
- return self._meter.schema_url
40
-
41
- def get_counter(self, name: str, description: str = "", unit: str = "") -> Counter:
42
- key = (name, description, unit)
43
- instrument = self._instruments.get(key)
44
- if not instrument:
45
- instrument = self._meter.create_counter(
46
- name=name,
47
- description=description,
48
- unit=unit,
49
- )
50
- self._instruments[key] = instrument
51
-
52
- return cast("Counter", instrument)
53
-
54
- def get_up_down_counter(
55
- self, name: str, description: str = "", unit: str = ""
56
- ) -> UpDownCounter:
57
- key = (name, description, unit)
58
- instrument = self._instruments.get(key)
59
- if not instrument:
60
- instrument = self._meter.create_up_down_counter(
61
- name=name,
62
- description=description,
63
- unit=unit,
64
- )
65
- self._instruments[key] = instrument
66
-
67
- return cast("UpDownCounter", instrument)
68
-
69
- def get_histogram(self, name: str, description: str = "", unit: str = "") -> Histogram:
70
- key = (name, description, unit)
71
- instrument = self._instruments.get(key)
72
- if not instrument:
73
- instrument = self._meter.create_histogram(
74
- name=name,
75
- description=description,
76
- unit=unit,
77
- )
78
- self._instruments[key] = instrument
79
-
80
- return cast("Histogram", instrument)
81
-
82
- def get_observable_counter(
83
- self,
84
- name: str,
85
- description: str = "",
86
- unit: str = "",
87
- observers: Optional[Sequence[ObserverType]] = None,
88
- ) -> ObservableCounter:
89
- key = (name, description, unit)
90
- instrument = self._instruments.get(key)
91
- if not instrument:
92
- instrument = self._meter.create_observable_counter(
93
- name=name,
94
- description=description,
95
- unit=unit,
96
- callbacks=observers,
97
- )
98
- self._instruments[key] = instrument
99
-
100
- return cast("ObservableCounter", instrument)
101
-
102
- def get_observable_up_down_counter(
103
- self,
104
- name: str,
105
- description: str = "",
106
- unit: str = "",
107
- observers: Optional[Sequence[ObserverType]] = None,
108
- ) -> ObservableUpDownCounter:
109
- key = (name, description, unit)
110
- instrument = self._instruments.get(key)
111
- if not instrument:
112
- instrument = self._meter.create_observable_up_down_counter(
113
- name=name,
114
- description=description,
115
- unit=unit,
116
- callbacks=observers,
117
- )
118
- self._instruments[key] = instrument
119
-
120
- return cast("ObservableUpDownCounter", instrument)
121
-
122
- def get_observable_gauge(
123
- self,
124
- name: str,
125
- description: str = "",
126
- unit: str = "",
127
- observers: Optional[Sequence[ObserverType]] = None,
128
- ) -> ObservableGauge:
129
- key = (name, description, unit)
130
- instrument = self._instruments.get(key)
131
- if not instrument:
132
- instrument = self._meter.create_observable_gauge(
133
- name=name,
134
- description=description,
135
- unit=unit,
136
- callbacks=observers,
137
- )
138
- self._instruments[key] = instrument
139
-
140
- return cast("ObservableGauge", instrument)
File without changes
@@ -1,40 +0,0 @@
1
- from dagster import DagsterError
2
- from dagster._utils.error import SerializableErrorInfo
3
- from grpc import Call as GrpcCall
4
-
5
-
6
- def extract_dagster_error_attributes(error: DagsterError) -> dict[str, str]:
7
- """Extracts attributes from a DagsterError that can be used for logging or metrics."""
8
- error_attributes = {
9
- "exception": type(error).__name__,
10
- }
11
-
12
- # DagsterError subtypes often have a field that contains a SerializableErrorInfo object
13
- # which identify the cause of the error. This field names vary between error types and is not
14
- # always present, but if they are they often identify the root cause of the error.
15
- for field in dir(error):
16
- if field.startswith("__"):
17
- # Skip magic methods and fields
18
- continue
19
-
20
- attr = getattr(error, field)
21
- if type(attr) is list and all(isinstance(item, SerializableErrorInfo) for item in attr):
22
- serializable_error_infos: list[SerializableErrorInfo] = getattr(error, field)
23
- for serializable_error_info in serializable_error_infos:
24
- if serializable_error_info.cause and serializable_error_info.cause.cls_name:
25
- error_attributes["cause"] = serializable_error_info.cause.cls_name
26
- return error_attributes
27
-
28
- # If not obtained from SerializableErrorInfo, use __cause__ to determine the error attributes
29
- if hasattr(error, "__cause__") and error.__cause__:
30
- error_cause = error.__cause__
31
- cause_name = type(error_cause).__name__
32
- if cause_name:
33
- error_attributes["cause"] = cause_name
34
-
35
- if isinstance(error_cause, GrpcCall):
36
- grpc_call: GrpcCall = error_cause
37
- code = grpc_call.code()
38
- error_attributes["code"] = code.name
39
-
40
- return error_attributes
@@ -1,178 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from contextlib import contextmanager
3
- from typing import Callable, Optional
4
-
5
- from dagster import DagsterError
6
- from dagster._time import get_current_timestamp
7
-
8
- from dagster_cloud.opentelemetry.controller import OpenTelemetryController
9
- from dagster_cloud.opentelemetry.observers.dagster_exception_handler import (
10
- extract_dagster_error_attributes,
11
- )
12
-
13
- ResultEvaluatorCallback = Callable[..., str]
14
-
15
-
16
- class ExecutionObserverInstruments:
17
- """OpenTelemetry instruments used to record generic code block executions."""
18
-
19
- def __init__(
20
- self, opentelemetry: OpenTelemetryController, metric_base_name: str, description: str
21
- ):
22
- self._meter = opentelemetry.get_meter(
23
- name=metric_base_name,
24
- attributes={
25
- "description": description,
26
- },
27
- )
28
-
29
- self._executions = self._meter.get_counter(
30
- name=metric_base_name,
31
- description=f"Number of {description}",
32
- )
33
-
34
- self._completions = self._meter.get_counter(
35
- name=f"{metric_base_name}.completions",
36
- description=f"Number of {description} completions by status",
37
- )
38
-
39
- self._exceptions = self._meter.get_counter(
40
- name=f"{metric_base_name}.exceptions",
41
- description=f"Number of exceptions caught in {description}",
42
- )
43
-
44
- self._duration = self._meter.get_histogram(
45
- name=f"{metric_base_name}.duration",
46
- description=f"Duration of {description}",
47
- unit="seconds",
48
- )
49
-
50
- @property
51
- def meter(self):
52
- """Get the OpenTelemetry meter. This is useful for adding custom metrics."""
53
- return self._meter
54
-
55
- @property
56
- def executions(self):
57
- """Get the OpenTelemetry counter for the number of executions of the observed code block."""
58
- return self._executions
59
-
60
- @property
61
- def completions(self):
62
- """Get the OpenTelemetry counter for the number of completions of the observed code block."""
63
- return self._completions
64
-
65
- @property
66
- def exceptions(self):
67
- """Get the OpenTelemetry counter for the number of exceptions caught in the observed code block."""
68
- return self._exceptions
69
-
70
- @property
71
- def duration(self):
72
- """Get the OpenTelemetry gauge for the duration of the observed code block."""
73
- return self._duration
74
-
75
-
76
- class ExecutionResultObserver(ABC):
77
- @abstractmethod
78
- def evaluate_result(self, *args, **kwargs):
79
- raise NotImplementedError("Subclasses must implement this method")
80
-
81
-
82
- class _NoopExecutionResultObserver(ExecutionResultObserver):
83
- """A no-op observer that does not record any metrics."""
84
-
85
- def evaluate_result(self, *args, **kwargs):
86
- pass
87
-
88
-
89
- class _DagsterExecutionResultObserver(ExecutionResultObserver):
90
- def __init__(
91
- self,
92
- instruments: ExecutionObserverInstruments,
93
- attributes: dict[str, str],
94
- result_evaluator_callback: Optional[ResultEvaluatorCallback] = None,
95
- ):
96
- self._result_evaluator_callback = result_evaluator_callback
97
- self._instruments = instruments
98
- self._attributes = attributes or {}
99
- self._status = None
100
-
101
- @property
102
- def meter(self):
103
- """Get the OpenTelemetry meter. This is useful for adding custom metrics."""
104
- return self._instruments.meter
105
-
106
- def evaluate_result(self, *args, **kwargs):
107
- """Evaluate the result of the observed code block.
108
-
109
- If a result evaluator callback is present, it will be called with the arguments passed to
110
- this method, as well as the attributes and instruments passed to the observer.
111
-
112
- If no result evaluator callback is present, the status will be set to "success".
113
- """
114
- if self._result_evaluator_callback:
115
- self._status = self._result_evaluator_callback(
116
- *args, attributes=self._attributes, instruments=self._instruments, **kwargs
117
- )
118
- else:
119
- self._status = "success"
120
-
121
- def set_status(self, status: str):
122
- self._status = status
123
-
124
- def get_status(self) -> Optional[str]:
125
- return self._status
126
-
127
-
128
- @contextmanager
129
- def observe_execution(
130
- opentelemetry: Optional[OpenTelemetryController],
131
- event_key: str,
132
- short_description: str,
133
- result_evaluator_callback: Optional[ResultEvaluatorCallback] = None,
134
- attributes: Optional[dict[str, str]] = None,
135
- ):
136
- """This context manager is used to observe the execution of a code block.
137
-
138
- It records the number of executions, completions, exceptions, and the duration of the code block.
139
- An optional evaluator callback can be provided to evaluate the result of the code block,
140
- setting a completion status and also optionally implementing other side effects such as
141
- recording additional metrics or logging based on the results.
142
- """
143
- attributes = attributes or {}
144
- if opentelemetry and opentelemetry.metrics_enabled:
145
- instruments = ExecutionObserverInstruments(
146
- opentelemetry=opentelemetry,
147
- metric_base_name=event_key,
148
- description=short_description,
149
- )
150
- instruments.executions.add(1, attributes)
151
-
152
- start_time = get_current_timestamp()
153
- observer = _DagsterExecutionResultObserver(
154
- instruments=instruments,
155
- attributes=attributes,
156
- result_evaluator_callback=result_evaluator_callback,
157
- )
158
-
159
- try:
160
- yield observer
161
- except DagsterError as e:
162
- err_attributes = extract_dagster_error_attributes(e)
163
- observer.set_status("exception")
164
- instruments.exceptions.add(1, attributes={**attributes, **err_attributes})
165
- raise
166
- except Exception as e:
167
- err_attributes = {"exception": type(e).__name__, **attributes}
168
- observer.set_status("exception")
169
- instruments.exceptions.add(1, err_attributes)
170
- raise
171
- finally:
172
- instruments.completions.add(
173
- 1, attributes={**attributes, "status": observer.get_status() or "unknown"}
174
- )
175
- instruments.duration.record(get_current_timestamp() - start_time, attributes)
176
-
177
- else:
178
- yield _NoopExecutionResultObserver()