// DevOps
Как недорого организовать сбор логов с удалённых клиентов по HTTP
Опубликовано 22.09.2026
Если приложение работает на сотнях клиентских устройств или у вас парк датчиков с телеметрией, рано или поздно понадобится видеть, что происходит на местах. Коммерческие системы вроде Splunk или Datadog для этого избыточны и дороги, а если клиенты умеют отправлять HTTP-запросы, большая часть задачи уже решена: HTTPS проходит почти через любой межсетевой экран, и нужен только сервер, который будет принимать логи.
Ниже — три недорогих способа организовать сбор логов по HTTP: от простого скрипта до бессерверного варианта. Общие принципы централизованного логирования разобраны в статье «Централизованное логирование: Часть 1 — Зачем собирать логи в одном месте».
Почему HTTP
- Универсальность — HTTP-клиент есть в любом языке программирования и на любой платформе.
- Простота — POST-запрос с JSON-телом легко сформировать и отладить.
- Доступность — порт 443 открыт почти везде, в отличие от портов syslog или GELF.
Используйте только HTTPS. Бесплатный сертификат Let’s Encrypt настраивается за несколько минут и защищает логи от перехвата; о бесплатных центрах сертификации см. статью «За пределами Let’s Encrypt».
Вариант 1. Скрипт на VPS
Самый простой способ, который разворачивается быстрее всего. Подходит для небольших проектов и небольшого числа клиентов.
Что потребуется
- Недорогой VPS у любого провайдера.
- Nginx и небольшое приложение на любом языке (Python/Flask, Node.js/Express, PHP).
Как это работает
Nginx принимает HTTPS-запросы и передаёт их приложению.
Приложение (около двадцати строк кода):
- принимает POST-запросы на
/log; - проверяет секретный ключ в заголовке
X-API-Key; - дописывает JSON в файл журнала.
- принимает POST-запросы на
Пример на Python (Flask)
from flask import Flask, request, abort
import os
import json
app = Flask(__name__)
API_KEY = os.environ["LOG_API_KEY"]
@app.route('/log', methods=['POST'])
def receive_log():
if request.headers.get('X-API-Key') != API_KEY:
abort(401)
data = request.get_json(silent=True)
if not data:
abort(400)
try:
with open("/var/log/my-app/events.log", "a") as f:
f.write(json.dumps(data) + "\n")
except Exception as e:
print(f"Failed to write log: {e}")
abort(500)
return "OK", 200
if __name__ == '__main__':
app.run(host='127.0.0.1', port=5000)Ключ берётся из переменной окружения LOG_API_KEY без значения по умолчанию: если переменная не задана, приложение не запустится, а не будет принимать логи со стандартным ключом. Встроенный сервер Flask подходит для проверки; в рабочей установке приложение запускают через WSGI-сервер (например, gunicorn).
Достоинства
- Минимальные затраты — стоимость самого дешёвого VPS.
- Полный контроль над хранением.
- Развёртывание за полчаса.
Недостатки
- Плохо масштабируется: запись в один файл быстро становится узким местом.
- Нужно обслуживание: ротация журналов, контроль диска, обновления.
- Анализ — вручную, через SSH и
grep.
Вариант 2. Сборщик Vector и хранилище Loki
Развитие первого варианта на готовых открытых компонентах.
Что потребуется
- VPS с 1–2 ГБ памяти.
- Vector, Loki и Grafana.
Как это работает
- Vector принимает логи по HTTP, обрабатывает и пересылает их.
- Loki хранит логи и индексирует только метки (labels), поэтому хранение обходится дёшево.
- Grafana — интерфейс для поиска и анализа логов на языке LogQL.
Подробнее о Loki и Grafana — в статье «Централизованное логирование: Часть 5 — Loki и Grafana».
Пример конфигурации Vector (vector.yaml)
У источника http_server есть два способа проверки доступа: basic (логин и пароль) и custom — проверка на языке VRL. Ниже ключ проверяется по заголовку X-API-Key через custom.
sources:
http_logs:
type: "http_server"
address: "0.0.0.0:8080"
decoding:
codec: "json"
auth:
strategy: "custom"
source: |-
.headers."x-api-key" == "super-secret-key"
transforms:
my_transform:
type: "remap"
inputs: ["http_logs"]
source: |
.app = "my_mobile_app"
if !exists(.level) { .level = "info" }
sinks:
loki:
type: "loki"
inputs: ["my_transform"]
endpoint: "http://localhost:3100"
labels:
app: "{{ app }}"
level: "{{ level }}"
encoding:
codec: "json"Замените super-secret-key на длинный случайный ключ. Vector в этом примере слушает порт 8080 по HTTP, поэтому перед ним должен стоять Nginx или другой обратный прокси с HTTPS, а сам порт 8080 не должен быть доступен из интернета.
Достоинства
- Высокая производительность.
- Поиск и фильтрация в Grafana.
- Vector умеет отправлять логи не только в Loki, но и в S3, ClickHouse и другие хранилища.
Недостатки
- Сложнее настройка: три компонента, которые нужно запускать через Docker или systemd и обновлять.
Вариант 3. Бессерверный
Сервер не нужен: оплачиваются только запросы и хранение.
Что потребуется
- Аккаунт в облаке. Для российских компаний доступен Yandex Cloud: Cloud Functions, API Gateway и Object Storage. Сервисы AWS и Google Cloud российские компании оплатить не могут.
- Стек (пример ниже — AWS): API Gateway + Lambda + S3. В Yandex Cloud схема та же: API Gateway вызывает Cloud Function, которая пишет в Object Storage через S3-совместимый API.
Как это работает
- Клиент отправляет POST-запрос.
- API Gateway принимает его на управляемом HTTP-адресе.
- Шлюз вызывает функцию.
- Функция сохраняет JSON в объектное хранилище, раскладывая файлы по дате.
Пример функции на Python (запись в S3)
import json
import boto3
import time
import os
s3 = boto3.client('s3')
BUCKET_NAME = os.environ['LOG_BUCKET_NAME']
def lambda_handler(event, context):
body = event.get('body')
if not body:
return {'statusCode': 400, 'body': 'No data'}
try:
log_data = json.loads(body)
except json.JSONDecodeError:
return {'statusCode': 400, 'body': 'Invalid JSON'}
now = time.strftime('%Y/%m/%d/%H', time.gmtime())
file_name = f"{context.aws_request_id}.json"
s3_key = f"logs/{now}/{file_name}"
try:
s3.put_object(
Bucket=BUCKET_NAME,
Key=s3_key,
Body=json.dumps(log_data),
ContentType='application/json'
)
return {'statusCode': 200, 'body': 'OK'}
except Exception as e:
print(e)
return {'statusCode': 500, 'body': 'Error saving log'}Достоинства
- При небольшом объёме логов затраты укладываются в бесплатные лимиты облака или близки к нулю — условия лимитов уточняйте у провайдера.
- Масштабирование без вашего участия.
- Нет серверов, которые нужно обновлять.
Недостатки
- Для анализа нужны дополнительные сервисы (например, Athena, BigQuery или запросы к хранилищу).
- Привязка к конкретному облачному провайдеру.
- Каждый запрос создаёт отдельный объект: при большом потоке логов это неэффективно, поэтому клиентам стоит отправлять логи пачками.
Рекомендации для клиента
- Асинхронная отправка — не блокируйте основной поток приложения.
- Отправка пачками — копите записи и отправляйте их, например, раз в 30 секунд или по 50 событий.
- Повторные попытки — сохраняйте неотправленные логи локально (например, в SQLite) и отправляйте позже.
- Фильтрация — отправляйте только нужные уровни (INFO, WARN, ERROR).
Итог
Собрать логи с удалённых клиентов можно недорого — нужно выбрать подход под задачу.
| Ситуация | Вариант |
|---|---|
| Проект только начинается | Бессерверный |
Уже есть VPS, хватает grep | Скрипт на VPS |
| Нужны поиск и анализ на своём сервере | Vector + Loki + Grafana |
// Contact
Нужна помощь?
Свяжись со мной и я помогу решить проблему
Написать в TelegramОтвечаю в течение рабочего дня (03:00–13:00 GMT)
Или оставьте заявку здесь:
// Related