← Назад к вопросам
Как отслеживать время http запросов?
2.2 Middle🔥 161 комментариев
#DevOps и инфраструктура#REST API и HTTP
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Отслеживание времени HTTP запросов
Отслеживание времени выполнения HTTP запросов критически важно для диагностики медленных запросов, выявления узких мест и оптимизации производительности приложения.
1. Встроенный модуль time
import time
import requests
def measure_http_request(url: str) -> dict:
"""Простое измерение времени запроса"""
start_time = time.time()
try:
response = requests.get(url, timeout=10)
total_time = time.time() - start_time
return {
"status_code": response.status_code,
"total_time_ms": total_time * 1000,
"response_size_bytes": len(response.content)
}
except requests.RequestException as e:
total_time = time.time() - start_time
return {
"error": str(e),
"total_time_ms": total_time * 1000
}
result = measure_http_request("https://api.github.com")
print(f"Время: {result['total_time_ms']:.2f}ms")
2. requests библиотека встроенная статистика
import requests
from urllib.parse import urlparse
def track_request_timing(url: str):
"""Использование elapsed из requests"""
response = requests.get(url)
# elapsed — общее время (от запроса до ответа)
print(f"Общее время: {response.elapsed.total_seconds():.3f}s")
print(f"Статус: {response.status_code}")
return response.elapsed.total_seconds()
track_request_timing("https://api.example.com/users")
3. Детальная диагностика с httpx
import httpx
import time
async def track_with_httpx(url: str):
"""httpx предоставляет детальную информацию о времени"""
async with httpx.AsyncClient() as client:
start = time.perf_counter()
response = await client.get(url)
elapsed = time.perf_counter() - start
print(f"Время соединения: не напрямую доступно")
print(f"Общее время: {elapsed * 1000:.2f}ms")
print(f"Размер: {len(response.content)} bytes")
# Синхронный вариант
def track_with_httpx_sync(url: str):
with httpx.Client() as client:
start = time.perf_counter()
response = client.get(url)
elapsed = time.perf_counter() - start
return {
"elapsed_ms": elapsed * 1000,
"status": response.status_code
}
result = track_with_httpx_sync("https://api.github.com")
print(f"Ответ получен за {result['elapsed_ms']:.2f}ms")
4. perf_counter для точного измерения
import time
import requests
from typing import Callable, Any
def measure_performance(func: Callable) -> Callable:
"""Декоратор для измерения времени выполнения"""
def wrapper(*args, **kwargs) -> tuple[Any, float]:
# perf_counter лучше для относительных времён
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
return result, elapsed * 1000 # в миллисекундах
return wrapper
@measure_performance
def fetch_user_data(user_id: int):
response = requests.get(f"https://api.example.com/users/{user_id}")
return response.json()
data, elapsed_ms = fetch_user_data(123)
print(f"Запрос выполнен за {elapsed_ms:.2f}ms")
5. Логирование с временными метками
import logging
import time
import requests
from datetime import datetime
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class HTTPLogger:
def __init__(self):
self.requests_log = []
def log_request(self, method: str, url: str, duration_ms: float, status_code: int = None):
"""Логирует информацию о запросе"""
timestamp = datetime.utcnow().isoformat()
entry = {
"timestamp": timestamp,
"method": method,
"url": url,
"duration_ms": duration_ms,
"status_code": status_code
}
self.requests_log.append(entry)
if duration_ms > 1000: # Если дольше 1 секунды
logger.warning(f"Медленный запрос: {method} {url} - {duration_ms:.2f}ms")
else:
logger.info(f"{method} {url} - {duration_ms:.2f}ms")
def get_slow_requests(self, threshold_ms: float = 500):
"""Возвращает запросы медленнее threshold"""
return [r for r in self.requests_log if r["duration_ms"] > threshold_ms]
# Использование
http_logger = HTTPLogger()
start = time.perf_counter()
response = requests.get("https://api.github.com")
elapsed = (time.perf_counter() - start) * 1000
http_logger.log_request("GET", "https://api.github.com", elapsed, response.status_code)
6. Session с автоматическим логированием
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
import logging
import time
logger = logging.getLogger(__name__)
class LoggingHTTPAdapter(HTTPAdapter):
"""HTTP адаптер с логированием времени"""
def send(self, request, *args, **kwargs):
start = time.perf_counter()
response = super().send(request, *args, **kwargs)
elapsed = (time.perf_counter() - start) * 1000
logger.info(
f"{request.method} {request.url} - "
f"Status: {response.status_code} - "
f"Time: {elapsed:.2f}ms"
)
return response
def create_session_with_logging():
"""Создаёт сессию с логированием"""
session = requests.Session()
adapter = LoggingHTTPAdapter(
max_retries=Retry(
total=3,
backoff_factor=0.5,
status_forcelist=[500, 502, 503, 504]
)
)
session.mount("https://", adapter)
session.mount("http://", adapter)
return session
# Использование
session = create_session_with_logging()
response = session.get("https://api.github.com")
7. Мониторинг с прометеус
from prometheus_client import Histogram, Counter
import requests
import time
# Метрики
http_request_duration = Histogram(
'http_request_duration_seconds',
'HTTP request duration',
['method', 'endpoint']
)
http_requests_total = Counter(
'http_requests_total',
'HTTP requests total',
['method', 'endpoint', 'status_code']
)
def fetch_with_metrics(method: str, url: str):
"""Запрос с метриками"""
start = time.time()
try:
response = requests.request(method, url)
duration = time.time() - start
# Записываем метрики
http_request_duration.labels(
method=method,
endpoint=url
).observe(duration)
http_requests_total.labels(
method=method,
endpoint=url,
status_code=response.status_code
).inc()
return response
except Exception as e:
duration = time.time() - start
http_request_duration.labels(
method=method,
endpoint=url
).observe(duration)
raise
fetch_with_metrics("GET", "https://api.example.com/users")
8. Контекстный менеджер для измерения
from contextlib import contextmanager
import time
from typing import Generator
@contextmanager
def time_tracker(operation_name: str) -> Generator[dict, None, None]:
"""Контекстный менеджер для отслеживания времени"""
timing_info = {"start": time.perf_counter()}
try:
yield timing_info
finally:
timing_info["end"] = time.perf_counter()
timing_info["duration_ms"] = (timing_info["end"] - timing_info["start"]) * 1000
print(f"{operation_name}: {timing_info['duration_ms']:.2f}ms")
# Использование
import requests
with time_tracker("API запрос"):
response = requests.get("https://api.github.com")
data = response.json()
9. Встроенный profiler
import cProfile
import pstats
import io
import requests
def profile_http_requests():
"""Профилирование всех операций"""
pr = cProfile.Profile()
pr.enable()
# Делаем несколько запросов
for i in range(5):
requests.get(f"https://api.github.com/users/user{i}")
pr.disable()
# Выводим результаты
s = io.StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats('cumulative')
ps.print_stats(10) # 10 самых медленных
print(s.getvalue())
profile_http_requests()
Best Practices
- Используй perf_counter() для точного относительного времени
- Логируй медленные запросы (> 500ms) отдельно
- Мониторьте тренды — используй Prometheus, DataDog
- Кешируйте результаты если возможно
- Используй таймауты — указывай timeout на все запросы
- Пулируйте соединения — переиспользуйте Session
Отслеживание времени запросов — основа оптимизации и надёжности приложения.