Флаг: English English

Дешево и сердито: как организовать сбор логов с удалённых клиентов по HTTP

Опубликовано 12.11.2025

У вас есть приложение, разбросанное по сотням клиентских устройств? Или парк IoT-датчиков, которые отправляют телеметрию? Рано или поздно возникает вопрос: «А что там вообще происходит?» И сразу за ним — «Как собрать логи, не разорившись на Splunk или Datadog?»

Если ваши клиенты способны отправлять HTTP-запросы, то у вас уже есть девяносто процентов решения. HTTP(S) — это универсальный и дружелюбный к брандмауэрам протокол. Всё, что нам требуется — это «слушатель» (endpoint), который будет принимать эти логи.

В этой статье мы разберём три бюджетных способа организовать сбор логов по HTTP — от «быстро, просто, но работает» до «масштабируемо и почти бесплатно».


Почему именно HTTP

  • Универсальность — HTTP-клиент есть в любом языке программирования и на любой платформе.
  • Простота — формат POST-запроса с JSON-телом интуитивно понятен.
  • Доступность — порт 443 (HTTPS) практически никогда не закрыт, в отличие от специфических портов для syslog или GELF.

Золотое правило: всегда используйте HTTPS. Бесплатные сертификаты Let’s Encrypt настраиваются за десять минут и защищают ваши данные от перехвата.


Вариант 1. Скрипт на VPS (быстро и очень дёшево)

Самый простой, «кустарный», но и самый быстрый в развёртывании способ. Подходит для пет-проектов или сбора логов с небольшого числа клиентов.

Что потребуется

  • Недорогой VPS (Vultr, DigitalOcean, Hetzner и другие) стоимостью около пяти долларов в месяц.
  • Стек: Nginx + любой бэкенд-скрипт (Python/Flask, Node.js/Express, PHP).

Как это работает

  1. Арендуете виртуальный сервер.

  2. Поднимаете Nginx как реверс-прокси и для терминирования SSL.

  3. Пишете крошечное веб-приложение (двадцать строк кода), которое:

    • принимает POST-запросы на /log;
    • при необходимости проверяет секретный ключ в заголовке X-API-Key;
    • записывает JSON-лог в файл.

Пример на Python (Flask)

from flask import Flask, request, abort
import os
import json

app = Flask(__name__)

API_KEY = os.environ.get("LOG_API_KEY", "super-secret-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)

Преимущества

  • Минимальные затраты (около пяти долларов в месяц).
  • Простота и контроль над хранением.
  • Развёртывание за полчаса.

Недостатки

  • Слабая масштабируемость: запись в один файл быстро становится узким местом.
  • Требуется обслуживание (ротация логов, мониторинг диска, безопасность).
  • Анализ — вручную через SSH и grep.

Вариант 2. Серверный сборщик (надёжно и гибко)

Эволюция первого варианта — используем готовый оптимизированный open-source стек.

Что потребуется

  • VPS за 5–10 долларов в месяц.
  • Стек: Vector, Loki, Grafana.

Как это работает

  1. Vector — это HTTP-сервер, принимающий логи.
  2. Loki — база логов от Grafana, индексирует только метки (labels), что делает хранение дешёвым.
  3. Grafana — удобный интерфейс для поиска и анализа логов с помощью LogQL.

Пример конфигурации Vector (vector.yaml)

sources:
  http_logs:
    type: "http"
    address: "0.0.0.0:8080"
    decoding:
      codec: "json"
    auth:
      strategy: "header"
      header_key: "X-API-Key"
      api_keys: ["super-secret-key"]

transforms:
  my_transform:
    type: "remap"
    inputs: ["http_logs"]
    source: |
      .app = "my_mobile_app"
      .level = get!(.level, default: "info")

sinks:
  loki:
    type: "loki"
    inputs: ["my_transform"]
    endpoint: "http://localhost:3100"
    labels:
      app: "{{ app }}"
      level: "{{ level }}"
    encoding:
      codec: "json"

Преимущества

  • Высокая производительность (тысячи логов в секунду).
  • Удобный поиск и фильтрация через Grafana.
  • Vector может отправлять логи не только в Loki, но и в S3, ClickHouse и другие хранилища.

Недостатки

  • Более сложная настройка: три компонента, требующих Docker или systemd.

Вариант 3. Serverless (почти бесплатно и бесконечно масштабируемо)

Самый современный и гибкий вариант. Никаких серверов — вы платите только за количество запросов и объём данных.

Что потребуется

  • Аккаунт в облаке (AWS, Google Cloud или Yandex Cloud).
  • Стек (на примере AWS): API Gateway + Lambda + S3 или CloudWatch Logs.

Как это работает

  1. Клиент отправляет POST-запрос.

  2. API Gateway принимает запрос как управляемый HTTP-эндпоинт.

  3. Он вызывает Lambda.

  4. Lambda:

    • сохраняет JSON в S3 по дате;
    • отправляет лог в CloudWatch Logs.

Пример Lambda на 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'}

Преимущества

  • Бесплатные лимиты AWS/Google/Yandex покрывают миллионы логов в месяц.
  • Автоматическая масштабируемость.
  • Нет серверов и обновлений — минимум обслуживания.

Недостатки

  • Анализ требует настройки (например, AWS Athena или BigQuery).
  • Привязка к конкретному облачному провайдеру (vendor lock-in).

Лучшие практики на стороне клиента

  1. Асинхронная отправка — не блокируйте основной поток приложения.
  2. Пакетная передача — собирайте логи в массив и отправляйте партиями (раз в 30 секунд или после 50 событий).
  3. Повторные попытки (retry) — сохраняйте офлайн-логи локально (например, в SQLite) и отправляйте их позже.
  4. Фильтрация — отправляйте только важные уровни (INFO, WARN, ERROR).

Заключение

Собрать логи с удалённых клиентов дёшево — вполне реально. Главное — выбрать подход под свои задачи.

СценарийРекомендация
Начинаете проектServerless
Уже есть VPS и нужен grepСкрипт на VPS
Требуется мощное self-hosted решениеVector + Loki

Нужна помощь?

Свяжись со мной и я помогу решить проблему

Похожие посты