Декоратор Python: логирование только медленных вызовов
Напишите решение на Python и проверьте его на странице.
Другие упражнения по этой теме: Декораторы Python: задачи на retry, rate limiter, кэш и Circuit Breaker.
Фильтрованная телеметрия операций
В системе мониторинга производительности отслеживается время выполнения ресурсоёмких операций с базой данных. Чтобы журнал не переполнялся тысячами штатных быстрых вызовов, параметризованный декоратор принимает порог длительности и функцию записи. Отчёт формируется и отправляется в приёмник телеметрии только тогда, когда время работы функции строго превысило заданный порог либо вызов завершился любым исключением.
Служебный приёмник не должен влиять на основной рабочий процесс: если при попытке записать отчёт возникает сбой, его следует безопасно подавить. Неполадка в приёмнике не должна мешать возврату вычисленного результата или заменять собой оригинальное исключение, возникшее в целевой функции.
Реализуйте фабрику декоратора профилирования, которая отбирает медленные и аварийные вызовы, изолирует ошибки приёмника телеметрии и сохраняет метаданные декорируемой функции.
Что уже дано
В среде выполнения уже определены вспомогательные инструменты проверки make_telemetry_probe и observe_telemetry_probe. Их реализовывать не нужно, они сразу доступны при запуске тестов.
Вам предстоит реализовать фабрику декоратора filtered_telemetry.
Что нужно сделать
Напишите функцию-фабрику filtered_telemetry(threshold, sink, clock).
Функция принимает три аргумента:
threshold— неотрицательный порог длительности в секундах (число от 0 до 1 000 000);sink— вызываемый объект-приёмник, принимающий словарь с отчётом;clock— функция монотонных часов без аргументов, возвращающая текущее числовое время в секундах.
Фабрика возвращает декоратор, который принимает целевую синхронную функцию func и возвращает функцию-обёртку wrapper(*args, **kwargs).
Правила работы обёртки:
- Аргументы
*argsи**kwargsпередаются вfuncбез изменений. Возвращённый результат или возникшее исключение должны быть полностью сохранены. - Замер времени охватывает строго выполнение
func: значениеduration_secondsвычисляется как разность показанийclock()сразу после завершения (или сбоя) функции и непосредственно перед её вызовом. Задержки внутриsinkне включаются в замер. Искусственные паузы (sleep) делать запрещено. - Отчёт отправляется в
sinkровно один раз при выполнении хотя бы одного из условий:
- Вызов
funcзавершился любым исключением (BaseException); - Вызов
funcзавершился успешно, но затраченное время строго большеthreshold(duration_seconds > threshold). Если время в точности равно порогу, успешный вызов не отправляется.
- Если успешный вызов уложился в порог (
duration_seconds <= threshold),sinkвызываться не должен. - Формат словаря, передаваемого в
sink: "function": имя функцииfunc.__name__;"duration_seconds": неотрицательное вычисленное время работы функции;"status": строка"success"при успешном завершении либо"error", если было возбуждено исключение;"error":Noneпри успехе, либо строка с именем типа возникшего исключения (type(exc).__name__).- Сбои приёмника изолированы: если
sinkвозбуждает любое исключение (подклассException), оно безопасно подавляется и ни при каких условиях не подменяет результат функции и не мешает всплытию исходного исключения изfunc. - Обёртка должна сохранять стандартные метаданные декорируемой функции через
functools.wraps: имя, документацию, аннотации типов, модуль, квалифицированное имя и ссылку__wrapped__наfunc.
Всего в рамках сессии может поступать от 0 до 1000 вызовов обёртки.
Ввод и вывод
Потоки stdin и stdout не используются: считывать ввод и печатать через print не требуется. После выполнения кода ученика тестирующая система считывает из глобального пространства имён функцию верхнего уровня filtered_telemetry и тестирует полученные обёртки на проверочных сценариях.
Пример использования
probe = make_telemetry_probe([["return", 5, "slow"], ["return", 1, "fast"]])
operation = filtered_telemetry(3, probe.sink, probe.clock)(probe.operation)
print(operation())
print(operation())
print(observe_telemetry_probe(probe)["reports"])
Вывод:
slow
fast
[{'function': 'operation', 'duration_seconds': 5, 'status': 'success', 'error': None}]
Без регистрации. Гостевая проверка не сохраняет прогресс. Для сохранения перейдите к уроку.
Отправьте решение, чтобы увидеть результаты тестов.
Связанные задачи
- Functools.wraps в Python: имя функции и атрибут wrapped
- Декоратор Circuit Breaker на Python: остановка вызовов после сбоев
- Декораторы Python: проверка цепочки wrapped и метаданных функции
- Кэширование Python: постройте ключ из выбранных аргументов функции
- Rate limiter на Python: декоратор со скользящим окном запросов
- Retry и fallback на Python: декоратор повторов с резервным вызовом
