Представьте типичную картину: приложение генерирует тысячи логов в минуту, и в интерфейсе мониторинга вы видите сотни групп, хотя по факту проблема одна. Причина проста: в каждое сообщение вшит уникальный идентификатор, имя продукта или число, и система воспринимает каждый вариант как отдельное событие.
User browsing product TSLA → группа #1User browsing product AAPL → группа #2User browsing product MSFT → группа #3
Один и тот же код, одна и та же логика — триста разных групп. Алерты бесполезны, анализ ошибок превращается в ручную работу.
Решение — grouping rules: правила, которые нормализуют сообщения до их группировки и извлекают переменные части как структурированные атрибуты. Никакого изменения кода приложения, никакой реинструментации.
В этой статье разберём синтаксис, все доступные типы и практические кейсы на примере Uptrace — OpenTelemetry-native APM с поддержкой трейсов, метрик и логов.
Синтаксис паттернов
Паттерн — это фиксированные слова вперемешку с плейсхолдерами
Фиксированные слова совпадают как есть:
error connecting to database
Плейсхолдеры находят переменные части по типу:
%{INT:status_code} → целое число, сохраняется как атрибут "status_code"%{UUID} → UUID, значение отбрасывается%{IP:remote_addr} → IP-адрес, сохраняется как "remote_addr"%{LOG_LEVEL:severity} → INFO / WARN / ERROR и т.д.
Формат: %{TYPE} без захвата, или %{TYPE:имя} с захватом значения в атрибут.
Паттерн для примера выше:
User browsing product %{IDENT:product}
Результат: одна группа вместо трёхсот, атрибут product на каждом событии — доступен для фильтрации, агрегации и алертов.
Доступные типы
|
Категория |
Типы |
|---|---|
|
Текст |
|
|
Числа |
|
|
Сеть |
|
|
Система |
|
|
Время |
|
|
Структура |
|
NUMBER и IP — виртуальные типы, они автоматически расширяются до всех подтипов. ANY+ захватывает один или несколько токенов любого типа, что удобно для переменных хвостов сообщения.
Полный справочник типов: uptrace.dev/features/logs/grouping
Извлечение атрибутов
Захваченные значения становятся структурированными атрибутами на каждом событии группы. Это открывает полноценную аналитику без изменения кода.
Пример лога корзины:
User a3f2c1d4-... adding 12 of product NVDA to cart
Паттерн:
User %{UUID} adding %{INT:num_products} of product %{IDENT:product} to cart
%{UUID} без имени просто поглощает идентификатор пользователя. num_products и product становятся атрибутами — в Uptrace можно сразу строить график max(num_products) по времени или фильтровать по product=NVDA.
Fingerprinting: отдельная группа на каждое уникальное значение
По умолчанию все логи, подходящие под паттерн, попадают в одну группу. Иногда нужно обратное: отдельная группа на каждое уникальное значение.
Добавьте # перед именем захвата:
%{IDENT:#function_name} failed
Теперь SendEmail failed и ParseConfig failed — две разные группы, каждая с собственным алертом. Без # они были бы одной группой.
Если имя не нужно — то же самое через опцию:
%{IDENT,fingerprint} failed
Практический пример — PostgreSQL unknown column:
%{LOG_LEVEL:log_severity} column %{QUOTED:#column} does not exist %{ATTR:sqlstate}
Исходные логи:
ERROR: column "event.created_at" does not exist (SQLSTATE=42703)ERROR: column "updated_at" does not exist (SQLSTATE=42703)
Результат: две группы, каждая алертируется независимо. Атрибуты log_severity и sqlstate доступны на каждом событии.
Опция unit: нормализация числовых значений
Если разные сервисы логируют длительности в разных единицах, опция unit нормализует значения автоматически:
%{NUMBER:duration,unit=ms}
Uptrace приводит значение к базовой единице и хранит консистентно, агрегации по сервисам работают без ручных конверсий.
Поддерживаемые единицы: ns, us, ms, s, bytes, kb, mb, gb, %, count, celsius и другие.
Опция extract: regex внутри quoted-строки
Когда лог содержит quoted-сообщение со структурированными данными внутри, опция extract позволяет достать их регулярным выражением:
ERROR %{QUOTED:msg,extract=`(?P<name>\w+) is (?P<age>\d+)`}
На строке ERROR "Alice is 25" правило захватит msg=Alice is 25, name=Alice, age=25. Полезно для легаси-логов, где несколько значений упакованы в одну строку.
Необязательные элементы и альтернативы
Паттерны не обязаны быть жёсткими. Чтобы сделать плейсхолдер необязательным, достаточно добавить ?:
error code %{NUMBER:code}? occurred
Совпадёт с error code 500 occurred и с error code occurred.
Альтернативы через |:
(%{LOG_LEVEL:level}|%{WORD:level}) %{WORD:msg}
Если один и тот же тип ошибки формулируется по-разному в разных сервисах — одно правило, несколько паттернов:
can't find item %{NUMBER:item_id}can not find item %{NUMBER:item_id}%{NUMBER:item_id} not found
Любое совпадение активирует правило.
Программная установка fingerprint
Для случаев, когда паттернов недостаточно, grouping.fingerprint можно выставить напрямую при создании события. Это переопределяет автоматически вычисленный fingerprint:
span.AddEvent("exception", trace.WithAttributes( attribute.String("exception.type", "*exec.ExitError"), attribute.String("exception.message", "exit status 1"), attribute.String("grouping.fingerprint", "exec.ExitError"),))
Когда использовать grouping rules
Подходит:
-
Высококардинальные сообщения с ID, именами, числами внутри
-
Нужны числовые агрегации по лог-данным (длительности, счётчики, размеры)
-
Алертинг на значение — отдельный алерт на каждую падающую функцию или неизвестную колонку
-
Легаси или сторонние логи без возможности реинструментации
Не подходит как замена:
-
Структурированному логированию — если можно эмитить
product=TSLAкак OpenTelemetry атрибут из приложения, лучше сделать это там -
Парсерам OpenTelemetry Logs и Vector для сложного разбора форматов
Как это выглядит в Uptrace
В Uptrace grouping rules находятся в разделе Logs & Errors → Grouping Rules. Вставляете сырое лог-сообщение, нажимаете Extract Pattern — система генерирует паттерн автоматически, вы только указываете имена для нужных плейсхолдеров.
Uptrace — OpenTelemetry-native APM для трейсов, метрик и логов. Grouping rules работают как в облачной версии, так и в self-hosted.
-
Cloud: uptrace.dev/get
-
Self-hosted (open source): uptrace.dev/get/hosted/install
ссылка на оригинал статьи https://habr.com/ru/articles/1034152/