Observability для Solana-бекенду вирішує одне ключове завдання: дає змогу відтворити шлях запиту від входу в ваш сервіс до фінального підтвердження транзакції в мережі та назад до відповіді клієнту. Без цього будь-який збій у production перетворюється на припущення. Нижче — покрокова інструкція, яка будує повну систему спостереження навколо бекенду, що взаємодіє з Solana RPC.
Три стовпи: логи, метрики, трасування
Кожен стовп відповідає на своє запитання. Логи пояснюють чому щось сталося, метрики показують наскільки це масштабно, трасування вказують де саме сталася затримка або помилка. У контексті Solana-бекенду ці стовпи мають специфіку.
Структуровані логи
Усі логи бекенду мають бути структурованими (JSON) і містити мінімальний набір полів: timestamp (UTC), level, service name, trace_id, span_id, message, контекстні атрибути. Для Solana-бекенду додатково обовʼязкові атрибути: transaction_signature (якщо є), rpc_method (наприклад, getBalance, sendTransaction), rpc_endpoint (який саме RPC-вузол обробляв запит).
Типова помилка — логувати всю відповідь від RPC без фільтрації. Відповіді getAccountInfo або getProgramAccounts можуть містити кілобайти даних, що засмічує лог-систему та ускладнює пошук. Логуйте лише метадані відповіді: статус, розмір payload, наявність помилки.
Метрики
Метрики поділяються на три категорії відносно Solana-бекенду:
- Метрики RPC-взаємодії: latency гістограми для кожного методу (
sendTransaction,simulateTransaction,getLatestBlockhash), кількість запитів за секунду, частота помилок 429 (rate limit) та 503 (сервіс недоступний). - Метрики транзакційного конвеєра: час від підготовки транзакції до її відправки, час від відправки до підтвердження (confirmation latency), частота drop-ів через timeout блокхешу, частота невдач симуляції (preflight failures).
- Метрики самого бекенду: розмір черг завдань, використання зʼєднань до RPC, кількість активних підписок (websocket subscriptions), memory/CPU стандартні метрики.
Критерій якості метрик: ви маєте здатність відповісти на запитання «скільки транзакцій за останню годину не отримали підтвердження через timeout блокхешу» одним запитом до системи метрик, без аналізу логів.
Трасування
Трасування (distributed tracing) повʼязує окремі події в єдиний ланцюжок. У Solana-бекенду один трейс зазвичай охоплює: отримання запиту від клієнта → підготовка інструкцій → запит блокхешу → симуляція транзакції → підписання → відправка → опитування статусу → обробка результату. Кожен етап — це окремий span у трейсі.
Ключове рішення: використовувати transaction signature як атрибут кореневого span. Це дозволяє пізніше корелювати трейс вашого бекенду з даними з блокчейн-експлорерів або власних індексерів.
Інтеграція з OpenTelemetry
OpenTelemetry (OTel) — стандартний інструментарій, що уніфікує збір трасувань, метрик і логів. Для Solana-бекенду на Rust або TypeScript це найприйнятніший вибір через екосистему експортерів.
Передумови та середовище
- Робоче середовище: Rust (stable toolchain) або Node.js 18+ для бекенду.
- OTel Collector розгорнутий як окремий сервіс (рекомендовано) або прямий експорт у бекенд системи (Grafana Tempo, Jaeger, Datadog).
- Доступ до endpointʼу OTLP (gRPC або HTTP) вашого колектора.
Налаштування для Rust-бекенду
Базовий набір залежностей у Cargo.toml:
tracing— фасад логування та трасування в екосистемі Rust.tracing-subscriber— реалізація підписника з підтримкою OTel.opentelemetry,opentelemetry-otlp,tracing-opentelemetry— інтеграція з OTel.
Архітектурно: tracing-subscriber ініціалізується з рівнем info для production (не debug — це генерує надмірний обсяг span-ів при кожному виклику RPC). Пропорцію семплінгу обирайте залежно від навантаження: для 100 RPS до RPC достатньо семплити 10–20% трасів повністю, решту — лише tail-based (зберігати трейс, якщо він містить помилку або затримку понад поріг).
Експортер налаштовується на OTLP gRPC з вашим колектором. Обовʼязково вкажіть timeout для експорту (рекомендовано 5–10 секунд), щоб збій колектора не блокував потоки бекенду.
Очікуваний результат: після відправки тестового запиту до вашого бекенду ви бачите повний трейс у UI колектора (Jaeger, Grafana Tempo) з усіма span-ами, включно з RPC-викликами.
Перевірка: викличте ендпоінт бекенду, який ініціює транзакцію. У UI трейсінгу знайдіть трейс за trace_id з логів бекенду. Перевірте наявність span-ів для кожного етапу.
Ризики: неправильне налаштування семплінгу призводить або до втрати даних (занижений %), або до перевантаження колектора та деградації бекенду (завищений %).
Відкат: якщо OTel-експортер викликає проблеми (затримки, паніки), переключіть tracing-subscriber на fmt (текстовий вивід у stdout) без втрати функціональності бекенду. Це вимагає умовної компіляції або feature flag.
Налаштування для TypeScript-бекенду
Використовується @opentelemetry/sdk-node з NodeSDK, який автоматично інструментує http, https, pg (якщо є БД). Для ручних span-ів навколо викликів Solana RPC використовуйте tracer.startSpan(). Експортер — @opentelemetry/exporter-trace-otlp-http або gRPC-варіант, залежно від вашого колектора.
Важливий нюанс: у Node.js async-середовищі легко втратити контекст трасування при використанні setTimeout, Promise.all з незалежними гілками або callback-стилю. Переконайтеся, що ваш HTTP-фреймворк (Fastify, Express з відповідним middleware) коректно пропагує контекст. Fastify робить це краще «з коробки».
Розподілене трасування транзакцій
Найскладніший етап observability для Solana — повʼязати події всередині вашого бекенду з подіями на стороні мережі Solana. Ваш бекенд не контролює валідатори, тому ви не можете додати свої span-и туди. Але ви можете побудувати кореляцію.
Модель span-ів для транзакції
Рекомендована ієрархія span-ів для операції відправки транзакції:
- Root span:
process_transaction_request— охоплює весь життєвий цикл від входу до виходу. Атрибутtx.signature додається після підписання. - Child span:
prepare_instructions— збір даних акаунтів, побудова інструкцій, обчислення PDA. - Child span:
fetch_blockhash— викликgetLatestBlockhash. ФіксуйтеblockhashтаlastValidBlockHeightяк атрибути. - Child span:
simulate_transaction— викликsimulateTransaction. Логуйте помилки симуляції якspan.set_status(Error)з деталями з відповіді RPC. - Child span:
send_and_confirm— відправка черезsendTransactionта опитування черезgetSignatureStatusesабоconfirmTransaction. Всередині — суб-span для кожного опитування.
Ця структура дозволяє побачити на таймлайні: чи витрачається час на підготовку, на симуляцію, на саму мережу, чи на очікування підтвердження.
Обробка специфічних помилок
Помилки в Solana-транзакціях мають конкретні причини, і трейс має їх фіксувати точно:
- Preflight failure: фіксується в span
simulate_transaction. Атрибутtx.simulation_errorмістить помилку з RPC (наприклад,InsufficientFundsForRent). Це не проблема мережі — це проблема логіки вашого бекенду. - Blockhash expired: фіксується в span
send_and_confirm. Причина — час міжgetLatestBlockhashта фактичною відправкою перевищив життєвий цикл блокхешу. Це вказує на затримку в пайплайні або на чергу відправки. - Transaction dropped: транзакція відправлена, але не потрапила в жоден блок протягом очікуваного часу. Причина може бути в MEV-ботах, перевантаженні мережі або недостатньому priority fee. Фіксуйте
tx.last_valid_block_heightта актуальнийslotна момент відмови.
Не групуйте ці помилки в загальний «transaction failed». Кожна має окремий патерн у трейсі та окремий сигнал для алертів.
Кореляція з зовнішніми джерелами
Після того як транзакція підтверджена, ви можете додати до span-у атрибут tx.slot та tx.block (якщо доступні з відповіді RPC). Це дозволяє знайти транзакцію в блокчейн-експлорері або корелювати з логами вашого індексера, якщо він працює окремо.
Якщо ваш бекенд отримує webhook-и або підписується на події через onLogs websocket, створюйте новий трейс з посиланням на оригінальний через links (OTel Links), а не як child span — це інший потік виконання.
Дашборди для різних ролей команди
Одна система observability, але різні уявлення даних залежно від того, хто дивиться. Спільне правило: кожен дашборд має фільтр за service name та часовим вікном «з коробки».
Дашборд розробника (Developer)
Фокус: що саме робить мій код і де він гальмує.
- Топ-10 найповільніших endpointʼів бекенду (p50, p95, p99 latency).
- Waterfall-діаграма типового трасу для ключових операцій (відправка транзакції, читання стану програми).
- Розподіл помилок симуляції за типом (групування за
errз відповіді RPC). - Кількість унікальних транзакцій за період проти кількості спроб відправки (показує retry rate).
Мета розробника — знайти bottlenecks у своєму коді, а не в мережі. Тому RPC latency показується окремо від загальної latency endpointʼу.
Дашборд SRE / інфраструктурної команди
Фокус: чи здоровий сервіс і чи витримує він навантаження.
- Загальний RPS бекенду та RPS до кожного RPC-endpointʼу.
- Черги: розмір внутрішньої черги транзакцій на відправку (якщо є пулінг), кількість активних websocket-підписок.
- Споживання ресурсів: memory бекенду (особливо при масових
getProgramAccounts), кількість відкритих TCP-зʼєднань до RPC. - Алерт-правила: latency p95 RPC > 2 секунд протягом 5 хвилин, error rate > 5%, черга відправки > 1000.
- Статус кожного RPC-endpointʼу (якщо використовується кілька провайдерів): uptime, середня latency, частота 429.
Критичний метрик для SRE: confirmation timeout rate — частота транзакцій, що не отримали підтвердження до lastValidBlockHeight. Це прямий показник того, що ваш бекенд або мережа не справляються з навантаженням.
Дашборд технічного фаундера
Фокус: чи виконується SLA та які операційні витрати.
- Загальний success rate транзакцій (відсоток підтверджених від загальної кількості ініційованих).
- Дотримання SLA: % запитів, що виконуються в межах узгодженого часу (наприклад, < 3 секунд енд-ту-енд).
- Динаміка навантаження за тиждень/місяць (для планування масштабування).
- Кількість інцидентів за період (на основі алертів) та середній час їх вирішення (MTTR).
Цей дашборд не містить технічних деталей трасувань. Він агрегує метрики в бізнес-контекст: «ми обробили X транзакцій із success rate Y% і SLA Z%».
Спільні принципи для всіх дашбордів
- Не розміщуйте більше 7–9 панелей на одному екрані. Решта — через drill-down.
- Кожна панель має зрозумілу назву з одиницею виміру (наприклад, «RPC latency, p95, ms», а не просто «Latency»).
- Усі часові рядки мають однаковий часовий інтервал на одному дашборді.
- Колірна схема: зелений — норма, жовтий — попередження, червоний — критично. Без інших кольорів для метрик.
Наступний логічний крок після побудови observability — інтеграція цих даних у алертинг-систему та налаштування автоматизованих реакцій (наприклад, переключення на резервний RPC-endpoint при деградації основного). Цей рівень автоматизації вимагає надійного клієнта для взаємодії з мережею, що розглядається в наступному матеріалі розділу.