Lambda-функції з'являються в OTTL
У міру того, як конвеєри телеметрії стають складнішими, трансформації, які вони повинні виконувати, також ускладнюються: очищення конфіденційних даних, нормалізація неузгоджених схем та забезпечення контрактів атрибутів. Хоча OTTL надає багатий набір функцій трансформації, вираження операцій над колекціями вимагало спеціалізованих функцій з жорстко закодованою поведінкою для кожного нового випадку використання.
OpenTelemetry Collector Contrib v0.157.0 змінює це, впроваджуючи лямбда-вирази в OTTL. Лямбди дозволяють користувачам передавати вбудовану логіку безпосередньо до узагальнених функцій вищого порядку, роблячи складні трансформації зібраних даних багаторазовими та лаконічними. Випуск включає вісім нових функцій, які використовують цю можливість: Filter, MapEach, MapKeys, Any, All, Find, Reduce та When.
Лямбда-вираз —— це невелика анонімна функція, визначена вбудовано, безпосередньо там, де вона використовується. Вона приймає список параметрів та тіло, яке може бути будь-яким дійсним виразом OTTL:
(key, value) => HasPrefix(key, "http.")
(key, value) => value * 2
Наступні приклади показують, що стало можливим завдяки цим функціям.
Фільтрація та трансформація колекцій
Раніше операції над кожним елементом зрізу або мапи вимагали спеціалізованих функцій з жорстко закодованою поведінкою. Тепер:
# Залишити лише атрибути, ключ яких починається з "http."
set(span.attributes, Filter(span.attributes, (k, _) => HasPrefix(k, "http.")))
# Перетворити всі значення атрибутів у рядки
set(span.attributes, MapEach(span.attributes, (_, v) => String(v)))
# Нормалізувати всі назви ключів атрибутів до snake_case
set(span.attributes, MapKeys(span.attributes, (k, _) => ToSnakeCase(k)))
# Додати префікс до всіх ключів атрибутів ресурсу
set(resource.attributes, MapKeys(resource.attributes, (k, _) => Format("app.%s", [k])))
Як ставити питання щодо зібраних даних
Any та All дозволяють використовувати вміст зрізу або мапи як умову, що відкриває правила фільтрації та речення where, які раніше були неможливі:
# Відхиляти відрізки, що походять з внутрішніх мереж
filter:
trace_conditions:
- Any(span.attributes["http.request.header.x-forwarded-for"],
(_, v) => IsInCIDR(v, ["10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"]))
# Обробляти лише відрізки, де всі значення db.* не порожні
transform:
trace_statements:
- set(span.attributes["db.complete"], true)
where All(span.attributes, (k, v) => not HasPrefix(k, "db.") or not IsEmpty(v))
Отримання одного значення
Find повертає перший елемент, який відповідає предикату. Додаткова друга лямбда трансформує результат перед поверненням:
# Знайти значення першого заголовка x-
set(span.attributes["custom_header"], Find(span.attributes, (k, _) => HasPrefix(k, "x-")))
# Знайти ключ першого атрибута, значення якого дорівнює "error"
set(log.attributes["error_key"], Find(log.attributes, (_, v) => v == "error", (k, _) => k))
Агрегація колекції
Reduce згортає зріз або мапу в єдине значення:
# Загальна кількість байтів у списку розмірів відповідей
- set(span.attributes["total_bytes"],
Reduce(span.attributes["response.sizes"], 0, (acc, _, v) => acc + v))
# Об'єднати всі повідомлення про помилки в один рядок
- set(log.attributes["errors"],
Reduce(log.attributes["error.messages"], "", (acc, _, v) => Format("%s; %s", acc, v)))
Вбудовані умовні вирази
When не базується на колекціях, але дотримується тієї ж ідеї.
# Замінити два вирази `set` одним
- set(span.attributes["speed_class"], When(() => (span.end_time_unix_nano -
span.start_time_unix_nano) > 1000000000, "slow", "fast"))
Комбінування функцій
Оскільки ці функції є композитними, ви можете передавати вихідні дані однієї функції безпосередньо як вхідні дані іншої. Тут Filter звужує мапу до атрибутів, які виглядають як PII, а MapEach хешує їхні значення перед обʼєднанням:
transform:
trace_statements:
- merge_maps(span.attributes,
MapEach(
Filter(span.attributes, (k, v) => IsMatch(k, "(?i)(email|phone|ssn|credit_card)")),
(_, v) => Format("%s (redacted)", [SHA1(String(v))])
), "upsert")
У поєднанні ці функції охоплюють широкий спектр трансформацій.
Спробуйте
Усі вісім функцій є експериментальними та доступні в OpenTelemetry Collector Contrib v0.157.0 за допомогою функціональної можливості:
--feature-gates=ottl.functions.enableLambda
Ми заохочуємо користувачів дослідити цю нову функціональність та скористатися її перевагами у своїх конвеєрах телеметрії!
Якщо у вас є питання або пропозиції, ми будемо раді почути вас! Долучайтеся до обговорення в каналі #otel-collector у CNCF Slack.