1
0
mirror of synced 2025-12-26 14:02:10 -05:00
Files
airbyte/airbyte-cdk/python/airbyte_cdk/utils/event_timing.py
Cole Snodgrass 2e099acc52 update headers from 2022 -> 2023 (#22594)
* It's 2023!

* 2022 -> 2023

---------

Co-authored-by: evantahler <evan@airbyte.io>
2023-02-08 13:01:16 -08:00

86 lines
2.3 KiB
Python

#
# Copyright (c) 2023 Airbyte, Inc., all rights reserved.
#
import datetime
import logging
import time
from contextlib import contextmanager
from dataclasses import dataclass, field
from typing import Optional
logger = logging.getLogger("airbyte")
class EventTimer:
"""Simple nanosecond resolution event timer for debugging, initially intended to be used to record streams execution
time for a source.
Event nesting follows a LIFO pattern, so finish will apply to the last started event.
"""
def __init__(self, name):
self.name = name
self.events = {}
self.count = 0
self.stack = []
def start_event(self, name):
"""
Start a new event and push it to the stack.
"""
self.events[name] = Event(name=name)
self.count += 1
self.stack.insert(0, self.events[name])
def finish_event(self):
"""
Finish the current event and pop it from the stack.
"""
if self.stack:
event = self.stack.pop(0)
event.finish()
else:
logger.warning(f"{self.name} finish_event called without start_event")
def report(self, order_by="name"):
"""
:param order_by: 'name' or 'duration'
"""
if order_by == "name":
events = sorted(self.events.values(), key=lambda event: event.name)
elif order_by == "duration":
events = sorted(self.events.values(), key=lambda event: event.duration)
text = f"{self.name} runtimes:\n"
text += "\n".join(str(event) for event in events)
return text
@dataclass
class Event:
name: str
start: float = field(default_factory=time.perf_counter_ns)
end: Optional[float] = field(default=None)
@property
def duration(self) -> float:
"""Returns the elapsed time in seconds or positive infinity if event was never finished"""
if self.end:
return (self.end - self.start) / 1e9
return float("+inf")
def __str__(self):
return f"{self.name} {datetime.timedelta(seconds=self.duration)}"
def finish(self):
self.end = time.perf_counter_ns()
@contextmanager
def create_timer(name):
"""
Creates a new EventTimer as a context manager to improve code readability.
"""
a_timer = EventTimer(name)
yield a_timer