Бібліотеки
OpenTelemetry надає бібліотеки інструментування для багатьох бібліотек, що зазвичай здійснюється через хуки бібліотек або monkey-патчинг коду бібліотек.
Нативна інструменталізація бібліотек з OpenTelemetry забезпечує кращу спостережуваність та досвід розробників для користувачів, усуваючи необхідність для бібліотек надавати та документувати хуки. Інші переваги, які надає нативна інструменталізація, включають:
- Користувацькі хуки для логування можуть бути замінені загальними та простими у використанні API OpenTelemetry, користувачі будуть взаємодіяти лише з OpenTelemetry.
- Трейси, логи, метрики з коду бібліотеки та застосунків корелюються та є узгодженими.
- Загальні домовленості дозволяють користувачам отримувати схожу та послідовну телеметрію в межах однієї технології та між бібліотеками та мовами.
- Сигнали телеметрії можуть бути точно налаштовані (відфільтровані, оброблені, агреговані) для різних сценаріїв споживання за допомогою широкого спектра добре задокументованих точок розширення OpenTelemetry.
Семантичні домовленості
Семантичні домовленості є основним джерелом правди про те, яка інформація включена у відрізки, створені веб-фреймворками, RPC-клієнтами, базами даних, клієнтами обміну повідомленнями, інфраструктурою тощо. Домовленості роблять інструменталізацію послідовною: користувачам, які працюють з телеметрією, не потрібно вивчати специфіку бібліотек, а постачальники спостережуваності можуть створювати досвід для широкого спектра технологій, наприклад, баз даних або систем обміну повідомленнями. Коли бібліотеки дотримуються домовленостей, багато сценаріїв можуть бути реалізовані без участі або налаштування користувача.
Семантичні домовленості постійно розвиваються, і нові домовленості постійно додаються. Якщо для вашої бібліотеки не існує деяких домовленостей, розгляньте можливість їх додавання. Особливу увагу приділяйте назвам відрізків: прагніть використовувати значущі назви та враховуйте важливість при їх визначенні. Також встановіть атрибут schema_url
, який ви можете використовувати для запису версії семантичних домовленостей, які ви використовуєте.
Якщо у вас є будь-які відгуки або ви хочете додати нову домовленість, долучайтеся до Instrumentation Slack або створіть тікет чи пул-реквест у репозиторії специфікацій.
Визначення відрізків
Думайте про вашу бібліотеку з погляду користувача бібліотеки та про те, що користувач може бути зацікавлений знати про поведінку та активність бібліотеки. Як підтримувач бібліотеки, ви знаєте внутрішню структуру, але користувач, швидше за все, буде менш зацікавлений у внутрішній роботі бібліотеки та більше зацікавлений у функціональності свого застосунку. Подумайте, яка інформація може бути корисною для аналізу використання вашої бібліотеки, а потім подумайте про відповідний спосіб моделювання цих даних. Деякі аспекти, які слід враховувати, включають:
- Відрізки та ієрархії відрізків
- Числові атрибути у відрізках, як альтернатива агрегованим метрикам
- Події відрізків
- Агреговані метрики
Наприклад, якщо ваша бібліотека робить запити до бази даних, створюйте відрізки лише для логічного запиту до бази даних. Фізичні запити через мережу повинні бути інструментовані в межах бібліотек, що реалізують цю функціональність. Ви також повинні віддавати перевагу захопленню інших активностей, таких як серіалізація обʼєктів/даних, як події відрізків, а не як додаткові відрізки.
Дотримуйтесь семантичних домовленостей при встановленні атрибутів відрізків.
Коли не варто інструментувати
Деякі бібліотеки є тонкими клієнтами, що обгортають мережеві виклики. Швидше за все, OpenTelemetry має бібліотеку інструментування для базового RPC-клієнта. Перегляньте реєстр, щоб знайти наявні бібліотеки. Якщо бібліотека існує, інструменталізація обгорткової бібліотеки може бути непотрібною.
Як загальне правило, інструментуйте вашу бібліотеку лише на її власному рівні. Не інструментуйте, якщо всі наступні випадки застосовуються:
- Ваша бібліотека є тонким проксі над задокументованими або самоочевидним API.
- OpenTelemetry має інструменталізацію для базових мережевих викликів.
- Немає домовленостей, яких ваша бібліотека повинна дотримуватися для збагачення телеметрії.
Коли сумніваєтесь, не інструментуйте. Якщо ви вирішите не інструментувати, все одно може бути корисно надати спосіб налаштування обробників OpenTelemetry для вашого внутрішнього RPC-клієнта. Це важливо в мовах, які не підтримують повністю автоматичну інструменталізацію, і все ще корисно в інших.
Решта цього документа надає рекомендації щодо того, що і як інструментувати у вашому застосунку.
API OpenTelemetry
Першим кроком при інструментуванні застосунку є включення пакета API OpenTelemetry як залежності.
OpenTelemetry має два основні модулі: API та SDK. API OpenTelemetry є набором абстракцій та неопераційних реалізацій. Якщо ваш застосунок не імпортує SDK OpenTelemetry, ваша інструменталізація нічого не робить і не впливає на продуктивність застосунку.
Бібліотеки повинні використовувати лише API OpenTelemetry
Якщо ви стурбовані додаванням нових залежностей, ось деякі міркування, які допоможуть вам вирішити, як мінімізувати конфлікти залежностей:
API OpenTelemetry Trace досяг стабільності на початку 2021 року. Він дотримується Semantic Versioning 2.0.
Використовуйте найранішу стабільну версію API OpenTelemetry (1.0.*) і уникайте її оновлення, якщо вам не потрібно використовувати нові функції.
Поки ваша інструменталізація стабілізується, розгляньте можливість її випуску як окремого пакету, щоб вона ніколи не викликала проблем для користувачів, які її не використовують. Ви можете зберігати її у вашому репозиторії або додати її до OpenTelemetry, щоб вона постачалася разом з іншими бібліотеками інструментування.
Семантичні домовленості є стабільними, але підлягають еволюції: хоча це не викликає жодних функціональних проблем, вам може знадобитися оновлювати вашу інструменталізацію час від часу. Маючи її у втулку або в репозиторії OpenTelemetry contrib, ви можете допомогти підтримувати домовленості в актуальному стані без порушень для ваших користувачів.
Отримання трейсера
Вся конфігурація застосунку прихована від вашої бібліотеки через API Tracer. Бібліотеки можуть дозволяти застосункам передавати екземпляри TracerProvider
для полегшення впровадження залежностей та спрощення тестування, або отримувати його з глобального TracerProvider
. Реалізації мов OpenTelemetry можуть мати різні переваги щодо передачі екземплярів або доступу до глобального на основі того, що є ідіоматичним для кожної мови програмування.
При отриманні трасера надайте назву та версію вашої бібліотеки (або втулка для трасування): вони зʼявляються в телеметрії та допомагають користувачам обробляти та фільтрувати телеметрію, розуміти, звідки вона походить, та налагоджувати або повідомляти про проблеми інструментування.
Що інструментувати
Публічні API
Публічні API є хорошими кандидатами для трасування: відрізки, створені для викликів публічних API, дозволяють користувачам зіставляти телеметрію з кодом застосунку, розуміти тривалість та результат викликів бібліотеки. Виклики трасування включають:
- Публічні методи, які роблять мережеві виклики внутрішні або локальні операції, які займають значний час і можуть зазнати невдачі, наприклад, введення/виведення.
- Обробники, які обробляють запити або повідомлення.
Приклад інструментування
Наступний приклад показує, як інструментувати Java-застосунок:
private static Tracer tracer = getTracer(TracerProvider.noop());
public static void setTracerProvider(TracerProvider tracerProvider) {
tracer = getTracer(tracerProvider);
}
private static Tracer getTracer(TracerProvider tracerProvider) {
return tracerProvider.getTracer("demo-db-client", "0.1.0-beta1");
}
private Response selectWithTracing(Query query) {
// ознайомтеся з домовленостями для отримання рекомендацій щодо назв відрізків та атрибутів
Span span = tracer.spanBuilder(String.format("SELECT %s.%s", dbName, collectionName))
.setSpanKind(SpanKind.CLIENT)
.setAttribute("db.name", dbName)
...
.startSpan();
// робить відрізок активним і дозволяє корелювати логи та вкладені відрізки
try (Scope unused = span.makeCurrent()) {
Response response = query.runWithRetries();
if (response.isSuccessful()) {
span.setStatus(StatusCode.OK);
}
if (span.isRecording()) {
// заповніть атрибути відповіді для кодів відповіді та іншої інформації
}
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR, e.getClass().getSimpleName());
throw e;
} finally {
span.end();
}
}
Дотримуйтесь домовленостей для заповнення атрибутів. Якщо немає відповідної, дивіться загальні домовленості.
Вкладені мережеві та інші відрізки
Мережеві виклики зазвичай трасуються за допомогою автоматичних інструменталізацій OpenTelemetry через відповідну реалізацію клієнта.
Якщо OpenTelemetry не підтримує трасування вашого мережевого клієнта, ось деякі міркування, які допоможуть вам вирішити щодо найкращого напрямку дій:
- Чи покращить трасування мережевих викликів спостережуваність для користувачів або вашу здатність підтримувати їх?
- Чи є ваша бібліотека обгорткою над публічним, задокументованим RPC API? Чи потрібно користувачам отримувати підтримку від базової служби у разі проблем?
- Інструментуйте бібліотеку та переконайтеся, що трасуєте окремі мережеві спроби.
- Чи буде трасування цих викликів за допомогою відрізків дуже докладним? чи помітно вплине на продуктивність?
- Використовуйте логи з докладністю або події відрізків: логи можуть бути корельовані з батьківським (публічні виклики API), тоді як події відрізків повинні бути встановлені на відрізок публічного API.
- Якщо вони повинні бути відрізками (щоб нести та поширювати унікальний контекст трасування), поставте їх за конфігураційною опцією та стандартно вимкніть.
Якщо OpenTelemetry вже підтримує трасування ваших мережевих викликів, ви, ймовірно, не хочете дублювати це. Можуть бути деякі винятки:
- Для підтримки користувачів без автоматичної інструментування, яка може не працювати в певних середовищах або коли користувачі мають занепокоєння щодо monkey-патчінгу.
- Для увімкнення користувацьких або застарілих протоколів кореляції та поширення контексту з базовою службою.
- Збагачення RPC відрізків важливою інформацією, специфічною для бібліотеки або служби, яка не охоплюється автоматичною інструменталізацією.
Універсальне рішення для уникнення дублювання знаходиться в розробці.
Події
Трейси є видом сигналу, який можуть надавати ваші застосунки. Події (або логи) та трейси доповнюють, а не дублюють один одного. Коли у вас є щось, що повинно мати певний рівень докладності, логи є кращим вибором, ніж трейси.
Якщо ваш застосунок використовує логування або подібний модуль, модуль логування може вже мати інтеграцію з OpenTelemetry. Щоб дізнатися, перегляньте реєстр. Інтеграції зазвичай проставляють активний контекст трасування на всіх логах, щоб користувачі могли їх корелювати.
Якщо ваша мова та екосистема не мають загальної підтримки логування, використовуйте події відрізків для спільного використання додаткових деталей застосунку. Події можуть бути більш зручними, якщо ви хочете додати атрибути також.
Як правило, використовуйте події або логи для докладних даних замість відрізків. Завжди прикріплюйте події до екземпляра відрізка, створеного вашою інструменталізацією. Уникайте використання активного відрізка, якщо можете, оскільки ви не контролюєте, до чого він відноситься.
Поширення контексту
Витяг контексту
Якщо ви працюєте над бібліотекою або службою, яка отримує вхідні виклики, такі як веб-фреймворк або споживач повідомлень, витягніть контекст з вхідного запиту або повідомлення. OpenTelemetry надає API Propagator
, який приховує специфічні стандарти поширення та зчитує контекст трасування на льоту. У випадку одної відповіді є лише один контекст, який стає батьком нового відрізка, створеного бібліотекою.
Після створення відрізка передайте новий контекст трасування до коду застосунку (зворотний виклик або обробник), зробивши відрізок активним; якщо можливо, зробіть це явно. Наступний приклад на Java показує, як додати контекст трасування та активувати відрізок. Дивіться Витяг контексту на Java для отримання додаткових прикладів.
// витяг контексту
Context extractedContext = propagator.extract(Context.current(), httpExchange, getter);
Span span = tracer.spanBuilder("receive")
.setSpanKind(SpanKind.SERVER)
.setParent(extractedContext)
.startSpan();
// робить відрізок активним, щоб будь-яка вкладена телеметрія була корельована
try (Scope unused = span.makeCurrent()) {
userCode();
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR);
throw e;
} finally {
span.end();
}
У випадку системи обміну повідомленнями ви можете отримати більше одного повідомлення одночасно. Отримані повідомлення стають посиланнями на відрізок, який ви створюєте. Дивіться домовленості обміну повідомленнями для отримання деталей.
Інʼєкція контексту
Коли ви робите вихідний виклик, ви зазвичай хочете поширити контекст до підлеглої служби. У цьому випадку створіть новий відрізок для трасування вихідного виклику та використовуйте API Propagator
для впровадження контексту в повідомлення. Можуть бути інші випадки, коли ви хочете впровадити контекст, наприклад, при створенні повідомлень для асинхронної обробки. Наступний приклад на Java показує, як поширити контекст. Дивіться Інʼєкція контексту у Java для отримання додаткових прикладів.
Span span = tracer.spanBuilder("send")
.setSpanKind(SpanKind.CLIENT)
.startSpan();
// робить відріхок активним, щоб будь-яка вкладена телеметрія була корельована
// навіть мережеві виклики можуть мати вкладені шари відрізків, логів або подій
try (Scope unused = span.makeCurrent()) {
// впровадження контексту
propagator.inject(Context.current(), transportLayer, setter);
send();
} catch (Exception e) {
span.recordException(e);
span.setStatus(StatusCode.ERROR);
throw e;
} finally {
span.end();
}
Можуть бути деякі винятки, коли вам не потрібно поширювати контекст:
- Підлегла служба не підтримує метадані або забороняє невідомі поля.
- Підлегла служба не визначає протоколи кореляції. Розгляньте можливість додавання підтримки поширення контексту в майбутній версії.
- Підлегла служба підтримує користувацький протокол кореляції.
- Найкраща спроба з користувацьким поширювачем: використовуйте контекст трасування OpenTelemetry, якщо він сумісний, або генеруйте та проставляйте користувацькі ідентифікатори кореляції у відрізку.
В процесі
- Робіть ваші відрізки активними або поточними, оскільки це дозволяє корелювати відрізки з логами та будь-якими вкладеними автоматичними інструменталізаціями.
- Якщо бібліотека має поняття контексту, підтримуйте опціональне явне поширення контексту трасування на застосунок до активних відрізків.
- Помістіть відрізки (контекст трасування), створені бібліотекою, у контекст явно, документуйте, як до нього отримати доступ.
- Дозвольте користувачам передавати контекст трасування у вашому контексті.
- У межах бібліотеки поширюйте контекст трасування явно. Активні відрізки можуть змінюватися під час зворотних викликів.
- Захоплюйте активний контекст від користувачів на поверхні публічного API якомога швидше, використовуйте його як батьківський контекст для ваших відрізків.
- Передавайте контекст і проставляйте атрибути, винятки, події на явно поширених екземплярах.
- Це важливо, якщо ви запускаєте потоки явно, виконуєте фонову обробку або інші речі, які можуть порушитися через обмеження асинхронного потоку контексту у вашій мові.
Додаткові міркування
Реєстр інструментування
Додайте вашу бібліотеку інструментування до реєстру OpenTelemetry, щоб користувачі могли її знайти.
Продуктивність
API OpenTelemetry є no-op і дуже продуктивним, коли в застосунку немає SDK. Коли SDK OpenTelemetry налаштований, він споживає обмежені ресурси.
Реальні застосунки, особливо на великому масштабі, часто мають налаштоване вибіркове трасування на основі заголовків. Вибіркові відрізки є доступними, і ви можете перевірити, чи відрізок записується, щоб уникнути додаткових виділень ресурсів та потенційно дорогих обчислень під час заповнення атрибутів. Наступний приклад Java показує, як надати атрибути для вибірки та перевірити запис відрізка.
// деякі атрибути важливі для вибірки, їх слід надавати під час створення
Span span = tracer.spanBuilder(String.format("SELECT %s.%s", dbName, collectionName))
.setSpanKind(SpanKind.CLIENT)
.setAttribute("db.name", dbName)
...
.startSpan();
// інші атрибути, особливо ті, що дорогі для обчислення
// слід додавати, якщо відрізок записується
if (span.isRecording()) {
span.setAttribute("db.statement", sanitize(query.statement()))
}
Обробка помилок
API OpenTelemetry не виходить з ладу на недійсних аргументах, ніколи не сповіщає про помилки і поглинає помилки, що означає, що він вибачає під час виконання. Таким чином, проблеми інструментування не впливають на логіку застосунку. Тестуйте інструменталізацію, щоб помітити проблеми, які OpenTelemetry приховує під час виконання.
Тестування
Оскільки OpenTelemetry має різноманітні автоматичні інструментування, спробуйте, як ваша інструменталізація взаємодіє з іншою телеметрією: вхідні запити, вихідні запити, логи тощо. Використовуйте типовий застосунок з популярними фреймворками та бібліотеками та увімкненим трасуванням під час спроби вашого інструментування. Перевірте, як подібні до ваших бібліотеки відображаються.
Для модульного тестування ви зазвичай можете зімітувати або підробити SpanProcessor
та SpanExporter
, як у наступному прикладі Java:
@Test
public void checkInstrumentation() {
SpanExporter exporter = new TestExporter();
Tracer tracer = OpenTelemetrySdk.builder()
.setTracerProvider(SdkTracerProvider.builder()
.addSpanProcessor(SimpleSpanProcessor.create(exporter)).build()).build()
.getTracer("test");
// run test ...
validateSpans(exporter.exportedSpans);
}
class TestExporter implements SpanExporter {
public final List<SpanData> exportedSpans = Collections.synchronizedList(new ArrayList<>());
@Override
public CompletableResultCode export(Collection<SpanData> spans) {
exportedSpans.addAll(spans);
return CompletableResultCode.ofSuccess();
}
...
}
Відгук
Чи це було корисним?
Дякуємо. Ми цінуємо ваші відгуки!
Будь ласка, дайте нам знати як ми можемо покращити цю сторінку. Ми цінуємо ваші відгуки!