|
11 | 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12 | 12 | # See the License for the specific language governing permissions and
|
13 | 13 | # limitations under the License.
|
| 14 | +# pylint: disable=too-many-lines |
| 15 | + |
14 | 16 | """
|
15 | 17 | Instrument to report system (CPU, memory, network) and
|
16 | 18 | process (CPU, memory, garbage collection) metrics. By default, the
|
|
45 | 47 | "process.runtime.cpu.time": ["user", "system"],
|
46 | 48 | "process.runtime.gc_count": None,
|
47 | 49 | "cpython.gc.collections": None,
|
| 50 | + "cpython.gc.collected_objects": None, |
| 51 | + "cpython.gc.uncollectable_objects": None, |
48 | 52 | "process.runtime.thread_count": None,
|
49 | 53 | "process.runtime.cpu.utilization": None,
|
50 | 54 | "process.runtime.context_switches": ["involuntary", "voluntary"],
|
|
138 | 142 | "process.runtime.cpu.time": ["user", "system"],
|
139 | 143 | "process.runtime.gc_count": None,
|
140 | 144 | "cpython.gc.collections": None,
|
| 145 | + "cpython.gc.collected_objects": None, |
| 146 | + "cpython.gc.uncollectable_objects": None, |
141 | 147 | "process.runtime.thread_count": None,
|
142 | 148 | "process.runtime.cpu.utilization": None,
|
143 | 149 | "process.runtime.context_switches": ["involuntary", "voluntary"],
|
@@ -199,6 +205,8 @@ def __init__(
|
199 | 205 | self._runtime_cpu_time_labels = self._labels.copy()
|
200 | 206 | self._runtime_gc_count_labels = self._labels.copy()
|
201 | 207 | self._runtime_gc_collections_labels = self._labels.copy()
|
| 208 | + self._runtime_gc_collected_objects_labels = self._labels.copy() |
| 209 | + self._runtime_gc_uncollectable_objects_labels = self._labels.copy() |
202 | 210 | self._runtime_thread_count_labels = self._labels.copy()
|
203 | 211 | self._runtime_cpu_utilization_labels = self._labels.copy()
|
204 | 212 | self._runtime_context_switches_labels = self._labels.copy()
|
@@ -486,6 +494,32 @@ def _instrument(self, **kwargs: Any):
|
486 | 494 | unit="{collection}",
|
487 | 495 | )
|
488 | 496 |
|
| 497 | + if "cpython.gc.collected_objects" in self._config: |
| 498 | + if self._python_implementation == "pypy": |
| 499 | + _logger.warning( |
| 500 | + "The cpython.gc.collected_objects metric won't be collected because the interpreter is PyPy" |
| 501 | + ) |
| 502 | + else: |
| 503 | + self._meter.create_observable_counter( |
| 504 | + name="cpython.gc.collected_objects", |
| 505 | + callbacks=[self._get_runtime_gc_collected_objects], |
| 506 | + description="The total number of objects collected since interpreter start.", |
| 507 | + unit="{object}", |
| 508 | + ) |
| 509 | + |
| 510 | + if "cpython.gc.uncollectable_objects" in self._config: |
| 511 | + if self._python_implementation == "pypy": |
| 512 | + _logger.warning( |
| 513 | + "The cpython.gc.uncollectable_objects metric won't be collected because the interpreter is PyPy" |
| 514 | + ) |
| 515 | + else: |
| 516 | + self._meter.create_observable_counter( |
| 517 | + name="cpython.gc.uncollectable_objects", |
| 518 | + callbacks=[self._get_runtime_gc_uncollectable_objects], |
| 519 | + description="The total number of uncollectable objects found since interpreter start.", |
| 520 | + unit="{object}", |
| 521 | + ) |
| 522 | + |
489 | 523 | if "process.runtime.thread_count" in self._config:
|
490 | 524 | self._meter.create_observable_up_down_counter(
|
491 | 525 | name=f"process.runtime.{self._python_implementation}.thread_count",
|
@@ -911,6 +945,32 @@ def _get_runtime_gc_collections(
|
911 | 945 | stat["collections"], self._runtime_gc_collections_labels.copy()
|
912 | 946 | )
|
913 | 947 |
|
| 948 | + def _get_runtime_gc_collected_objects( |
| 949 | + self, options: CallbackOptions |
| 950 | + ) -> Iterable[Observation]: |
| 951 | + """Observer callback for garbage collection collected objects""" |
| 952 | + for index, stat in enumerate(gc.get_stats()): |
| 953 | + self._runtime_gc_collected_objects_labels["generation"] = str( |
| 954 | + index |
| 955 | + ) |
| 956 | + yield Observation( |
| 957 | + stat["collected"], |
| 958 | + self._runtime_gc_collected_objects_labels.copy(), |
| 959 | + ) |
| 960 | + |
| 961 | + def _get_runtime_gc_uncollectable_objects( |
| 962 | + self, options: CallbackOptions |
| 963 | + ) -> Iterable[Observation]: |
| 964 | + """Observer callback for garbage collection uncollectable objects""" |
| 965 | + for index, stat in enumerate(gc.get_stats()): |
| 966 | + self._runtime_gc_uncollectable_objects_labels["generation"] = str( |
| 967 | + index |
| 968 | + ) |
| 969 | + yield Observation( |
| 970 | + stat["uncollectable"], |
| 971 | + self._runtime_gc_uncollectable_objects_labels.copy(), |
| 972 | + ) |
| 973 | + |
914 | 974 | def _get_runtime_thread_count(
|
915 | 975 | self, options: CallbackOptions
|
916 | 976 | ) -> Iterable[Observation]:
|
|
0 commit comments