logboard/docs/api.md
Сергей Антропов 5c8efe2644 Добавлена полная документация проекта LogBoard+
- Создан основной README.md с описанием проекта
- Добавлена подробная документация в папке docs/
- Создан файл LICENSE (MIT)
- Обновлен .gitignore
- Добавлена документация по безопасности с генерацией ключей
- Включены примеры конфигураций и устранение неполадок

Автор: Сергей Антропов
Сайт: https://devops.org.ru
2025-08-19 01:06:23 +03:00

658 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# API Документация LogBoard+
**Автор:** Сергей Антропов
**Сайт:** https://devops.org.ru
## Содержание
1. [Обзор API](#обзор-api)
2. [Аутентификация](#аутентификация)
3. [REST API](#rest-api)
4. [WebSocket API](#websocket-api)
5. [Коды ошибок](#коды-ошибок)
6. [Примеры использования](#примеры-использования)
## Обзор API
LogBoard+ предоставляет REST API и WebSocket API для работы с логами Docker контейнеров.
### Базовый URL
```
http://localhost:9001
```
### Форматы данных
- **Content-Type:** `application/json`
- **Кодировка:** UTF-8
- **Временные метки:** ISO 8601 (UTC)
### Аутентификация
Все API endpoints (кроме `/healthz` и `/api/auth/login`) требуют JWT токен в заголовке:
```
Authorization: Bearer <token>
```
## Аутентификация
### POST /api/auth/login
Вход в систему и получение JWT токена.
**Запрос:**
```json
{
"username": "admin",
"password": "your-password"
}
```
**Ответ:**
```json
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "bearer"
}
```
**Пример curl:**
```bash
curl -X POST "http://localhost:9001/api/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"your-password"}'
```
### POST /api/auth/logout
Выход из системы (удаление токена из cookies).
**Ответ:**
```json
{
"message": "Успешный выход из системы"
}
```
### GET /api/auth/me
Получение информации о текущем пользователе.
**Заголовки:**
```
Authorization: Bearer <token>
```
**Ответ:**
```json
{
"username": "admin"
}
```
## REST API
### Контейнеры и сервисы
#### GET /api/services
Получение списка всех контейнеров.
**Параметры запроса:**
| Параметр | Тип | Описание | По умолчанию |
|----------|-----|----------|--------------|
| `projects` | string | Фильтр по проектам (через запятую) | Все проекты |
| `include_stopped` | boolean | Включить остановленные контейнеры | false |
**Пример запроса:**
```bash
curl -X GET "http://localhost:9001/api/services?projects=myproject&include_stopped=true" \
-H "Authorization: Bearer YOUR_TOKEN"
```
**Ответ:**
```json
[
{
"id": "abc123def456",
"name": "myproject_web_1",
"status": "running",
"image": "nginx:latest",
"service": "web",
"project": "myproject",
"health": "healthy",
"ports": ["80/tcp"],
"url": "http://localhost:8080",
"host_port": "8080"
},
{
"id": "def456ghi789",
"name": "myproject_db_1",
"status": "running",
"image": "postgres:13",
"service": "db",
"project": "myproject",
"health": "healthy",
"ports": ["5432/tcp"],
"url": null,
"host_port": null
}
]
```
#### GET /api/projects
Получение списка всех проектов Docker Compose.
**Ответ:**
```json
[
"myproject",
"another-project",
"standalone"
]
```
### Логи
#### GET /api/logs/{container_id}
Получение логов контейнера.
**Параметры пути:**
- `container_id` - ID контейнера (первые 12 символов)
**Параметры запроса:**
| Параметр | Тип | Описание | По умолчанию |
|----------|-----|----------|--------------|
| `tail` | string | Количество строк или 'all' | 500 |
| `since` | string | Время начала (ISO 8601 или относительное) | null |
**Пример запроса:**
```bash
curl -X GET "http://localhost:9001/api/logs/abc123def456?tail=100&since=2024-01-15T10:00:00Z" \
-H "Authorization: Bearer YOUR_TOKEN"
```
**Ответ:**
```json
{
"container": {
"id": "abc123def456",
"name": "myproject_web_1",
"status": "running",
"image": "nginx:latest",
"created": "2024-01-15T09:00:00.000000000Z",
"state": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 1234,
"ExitCode": 0,
"Error": "",
"StartedAt": "2024-01-15T09:00:00.000000000Z",
"FinishedAt": "0001-01-01T00:00:00Z"
}
},
"logs": [
{
"timestamp": "2024-01-15T10:30:15.123456789Z",
"message": "2024/01/15 10:30:15 [notice] 1#1: start worker processes",
"raw": "2024-01-15T10:30:15.123456789Z 2024/01/15 10:30:15 [notice] 1#1: start worker processes"
},
{
"timestamp": "2024-01-15T10:30:15.123456789Z",
"message": "2024/01/15 10:30:15 [notice] 1#1: start worker process 1234",
"raw": "2024-01-15T10:30:15.123456789Z 2024/01/15 10:30:15 [notice] 1#1: start worker process 1234"
}
],
"total_lines": 2,
"tail": "100",
"since": "2024-01-15T10:00:00Z",
"timestamp": "2024-01-15T10:30:15.123456789Z"
}
```
#### GET /api/logs/stats/{container_id}
Получение статистики логов контейнера.
**Ответ:**
```json
{
"debug": 15,
"info": 42,
"warn": 8,
"error": 3
}
```
### Управление
#### GET /api/settings
Получение настроек приложения.
**Ответ:**
```json
{
"ajax_update_interval": 2000,
"default_tail": 500,
"skip_unhealthy": true
}
```
#### GET /api/excluded-containers
Получение списка исключенных контейнеров.
**Ответ:**
```json
{
"excluded_containers": [
"noisy-container-1",
"noisy-container-2"
]
}
```
#### POST /api/excluded-containers
Обновление списка исключенных контейнеров.
**Запрос:**
```json
[
"noisy-container-1",
"noisy-container-2",
"another-noisy-container"
]
```
**Ответ:**
```json
{
"status": "success",
"message": "Список исключенных контейнеров обновлен"
}
```
#### POST /api/snapshot
Создание снимка логов.
**Запрос:**
```json
{
"container_id": "abc123def456",
"service": "web",
"content": "Логи контейнера..."
}
```
**Ответ:**
```json
{
"file": "web-20240115-103015.log",
"url": "/snapshots/web-20240115-103015.log"
}
```
### Системные
#### GET /healthz
Health check endpoint.
**Ответ:**
```
ok
```
## WebSocket API
### Подключение
Все WebSocket endpoints требуют JWT токен в параметре `token`.
### ws://host:port/ws/logs/{container_id}
Получение логов отдельного контейнера.
**Параметры:**
- `container_id` - ID контейнера
- `tail` - Количество строк (по умолчанию 500)
- `token` - JWT токен
- `service` - Имя сервиса (опционально)
- `project` - Имя проекта (опционально)
**Пример подключения:**
```javascript
const token = "your-jwt-token";
const containerId = "abc123def456";
const ws = new WebSocket(`ws://localhost:9001/ws/logs/${containerId}?token=${token}&tail=100`);
ws.onmessage = function(event) {
console.log('Получены логи:', event.data);
};
ws.onerror = function(error) {
console.error('WebSocket ошибка:', error);
};
```
### ws://host:port/ws/fan/{service_name}
Получение логов сервиса (все реплики).
**Параметры:**
- `service_name` - Имя сервиса Docker Compose
- `tail` - Количество строк (по умолчанию 500)
- `token` - JWT токен
- `project` - Имя проекта (опционально)
**Пример подключения:**
```javascript
const token = "your-jwt-token";
const serviceName = "web";
const ws = new WebSocket(`ws://localhost:9001/ws/fan/${serviceName}?token=${token}&tail=100`);
ws.onmessage = function(event) {
console.log('Логи сервиса:', event.data);
};
```
### ws://host:port/ws/fan_group
Получение логов группы сервисов.
**Параметры:**
- `services` - Имена сервисов через запятую
- `tail` - Количество строк (по умолчанию 500)
- `token` - JWT токен
- `project` - Имя проекта (опционально)
**Пример подключения:**
```javascript
const token = "your-jwt-token";
const services = "web,db,redis";
const ws = new WebSocket(`ws://localhost:9001/ws/fan_group?services=${services}&token=${token}&tail=100`);
ws.onmessage = function(event) {
console.log('Логи группы сервисов:', event.data);
};
```
## Коды ошибок
### HTTP коды состояния
| Код | Описание |
|-----|----------|
| 200 | Успешный запрос |
| 400 | Неверный запрос |
| 401 | Не авторизован |
| 403 | Доступ запрещен |
| 404 | Ресурс не найден |
| 500 | Внутренняя ошибка сервера |
### Формат ошибок
```json
{
"error": "error_type",
"message": "Описание ошибки",
"details": "Дополнительная информация"
}
```
### Примеры ошибок
#### 401 Unauthorized
```json
{
"error": "unauthorized",
"message": "Требуется авторизация",
"details": "Для доступа к этому API необходимо войти в систему."
}
```
#### 404 Not Found
```json
{
"error": "http_404",
"message": "Контейнер не найден",
"details": "URL: /api/logs/invalid-id"
}
```
#### 500 Internal Server Error
```json
{
"error": "http_500",
"message": "Ошибка подключения к Docker",
"details": "URL: /api/services"
}
```
## Примеры использования
### Python
```python
import requests
import json
# Базовый URL
BASE_URL = "http://localhost:9001"
# Аутентификация
def login(username, password):
response = requests.post(f"{BASE_URL}/api/auth/login", json={
"username": username,
"password": password
})
return response.json()["access_token"]
# Получение списка контейнеров
def get_containers(token):
headers = {"Authorization": f"Bearer {token}"}
response = requests.get(f"{BASE_URL}/api/services", headers=headers)
return response.json()
# Получение логов контейнера
def get_logs(token, container_id, tail=100):
headers = {"Authorization": f"Bearer {token}"}
params = {"tail": tail}
response = requests.get(f"{BASE_URL}/api/logs/{container_id}",
headers=headers, params=params)
return response.json()
# Использование
token = login("admin", "your-password")
containers = get_containers(token)
print(f"Найдено контейнеров: {len(containers)}")
for container in containers:
logs = get_logs(token, container["id"], tail=10)
print(f"Контейнер {container['name']}: {len(logs['logs'])} строк логов")
```
### JavaScript
```javascript
// Класс для работы с LogBoard+ API
class LogBoardAPI {
constructor(baseUrl, token) {
this.baseUrl = baseUrl;
this.token = token;
this.headers = {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
};
}
// Получение списка контейнеров
async getContainers(projects = null, includeStopped = false) {
const params = new URLSearchParams();
if (projects) params.append('projects', projects);
if (includeStopped) params.append('include_stopped', 'true');
const response = await fetch(`${this.baseUrl}/api/services?${params}`, {
headers: this.headers
});
return await response.json();
}
// Получение логов контейнера
async getLogs(containerId, tail = 100, since = null) {
const params = new URLSearchParams();
params.append('tail', tail);
if (since) params.append('since', since);
const response = await fetch(`${this.baseUrl}/api/logs/${containerId}?${params}`, {
headers: this.headers
});
return await response.json();
}
// Получение статистики логов
async getLogStats(containerId) {
const response = await fetch(`${this.baseUrl}/api/logs/stats/${containerId}`, {
headers: this.headers
});
return await response.json();
}
// WebSocket для live-логов
createLogsWebSocket(containerId, tail = 100) {
const ws = new WebSocket(
`ws://${this.baseUrl.replace('http://', '')}/ws/logs/${containerId}?token=${this.token}&tail=${tail}`
);
return ws;
}
}
// Использование
async function main() {
// Получение токена
const loginResponse = await fetch('http://localhost:9001/api/auth/login', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
username: 'admin',
password: 'your-password'
})
});
const {access_token} = await loginResponse.json();
// Создание API клиента
const api = new LogBoardAPI('http://localhost:9001', access_token);
// Получение контейнеров
const containers = await api.getContainers();
console.log('Контейнеры:', containers);
// Получение логов первого контейнера
if (containers.length > 0) {
const logs = await api.getLogs(containers[0].id, 50);
console.log('Логи:', logs);
// WebSocket для live-логов
const ws = api.createLogsWebSocket(containers[0].id, 100);
ws.onmessage = (event) => {
console.log('Новые логи:', event.data);
};
}
}
main().catch(console.error);
```
### cURL
```bash
#!/bin/bash
# Переменные
BASE_URL="http://localhost:9001"
USERNAME="admin"
PASSWORD="your-password"
# Получение токена
TOKEN=$(curl -s -X POST "$BASE_URL/api/auth/login" \
-H "Content-Type: application/json" \
-d "{\"username\":\"$USERNAME\",\"password\":\"$PASSWORD\"}" \
| jq -r '.access_token')
echo "Токен получен: ${TOKEN:0:20}..."
# Получение списка контейнеров
echo "Получение списка контейнеров..."
curl -s -X GET "$BASE_URL/api/services" \
-H "Authorization: Bearer $TOKEN" \
| jq '.[] | {name: .name, status: .status, project: .project}'
# Получение логов первого контейнера
CONTAINER_ID=$(curl -s -X GET "$BASE_URL/api/services" \
-H "Authorization: Bearer $TOKEN" \
| jq -r '.[0].id')
echo "Получение логов контейнера $CONTAINER_ID..."
curl -s -X GET "$BASE_URL/api/logs/$CONTAINER_ID?tail=10" \
-H "Authorization: Bearer $TOKEN" \
| jq '.logs[] | .message'
```
## Ограничения и рекомендации
### Ограничения
- Максимальное количество строк логов: 10000
- Таймаут WebSocket соединения: 60 секунд
- Максимальный размер снимка логов: 10 MB
### Рекомендации
1. **Используйте фильтрацию по времени** для больших объемов логов
2. **Настройте исключение контейнеров** с избыточным логированием
3. **Используйте WebSocket** для real-time мониторинга
4. **Регулярно очищайте снимки логов** для экономии места
### Производительность
- REST API: до 1000 запросов в минуту
- WebSocket: до 100 одновременных соединений
- Размер ответа: до 1 MB на запрос