Afilters: Difference between revisions
m (minor fixes after partial review) |
|||
| Line 1: | Line 1: | ||
= Advanced filters = | |||
Поле "Расширенный фильтр" в пользовательских фильтрах предназначено для фильтрации маркеров (предупреждений) по сложным предикатам. | Поле "Расширенный фильтр" в пользовательских фильтрах предназначено для фильтрации маркеров (предупреждений) по сложным предикатам. | ||
[[File:Image-afilters-prop.png|thumb]] | [[File:Image-afilters-prop.png|thumb]] | ||
| Line 5: | Line 5: | ||
* поля маркера, его трассы, разметки и комментариев | * поля маркера, его трассы, разметки и комментариев | ||
* информацию из контекста | * информацию из контекста: имя проекта, ветки, снимка и т. п. | ||
* атрибуты снимка | * атрибуты снимка, включая пользовательские атрибуты, заданные при импорте | ||
* статусы разметки | * статусы разметки | ||
* текст и атрибуты комментариев | * текст и атрибуты комментариев | ||
Формат фильтра определяется следующим шаблоном: | Формат фильтра определяется следующим шаблоном: | ||
filter(markers, <predicate expr>) | |||
Выражение <code><predicate expr></code> определяет предикат. Объект <code>markers</code> содержит массив маркеров из контекста, функция <code>filter</code> фильтрует данный список по предикату. Таким образом, применение фильтра заключается в фильтрации списка маркеров по указанному предикату. | Выражение <code><predicate expr></code> определяет предикат. Объект <code>markers</code> содержит массив маркеров из контекста, функция <code>filter</code> фильтрует данный список по предикату. Таким образом, применение фильтра заключается в фильтрации списка маркеров по указанному предикату. | ||
| Line 18: | Line 20: | ||
=== Поля маркера (предупреждения) === | === Поля маркера (предупреждения) === | ||
* <code>Comments</code> | * <code>Comments</code> — список комментариев маркера. Объект типа Comment (смотрите ниже) | ||
* <code>Details</code> | * <code>Details</code> — информация, специфичная для анализатора. Ближайший аналог — fingerprint в SARIF | ||
* <code>File</code> | * <code>File</code> — имя файла | ||
* <code>Function</code> | * <code>Function</code> — имя функции, может быть mangled для С++ | ||
* <code>ID</code> | * <code>ID</code> — UUID маркера | ||
* <code>Invariant</code> | * <code>Invariant</code> — инвариант маркера. Используется для автопереноса разметки между снимками | ||
* <code>Lang</code> | * <code>Lang</code> — язык детектора | ||
* <code>Line</code> | * <code>Line</code> — номер строки в файле | ||
* <code>LocID</code> | * <code>LocID</code> — порядковый номер маркера относительно изначального отчета анализатора | ||
* <code>MTid</code> | * <code>MTid</code> — шаблон сообщения | ||
* <code>Msg</code> | * <code>Msg</code> — текст сообщения | ||
* <code>OrigFunc</code> | * <code>OrigFunc</code> — 'человекочитаемое' имя функции. Может быть недоступно | ||
* <code>Tags</code> | * <code>Tags</code> — список тегов (меток) маркера | ||
* <code>Tool</code> | * <code>Tool</code> — модуль анализатора, ответственного за данный детектор | ||
* <code>Traces</code> | * <code>Traces</code> — список трасс маркера. Объект типа Trace (смотрите ниже) | ||
* <code>WarnClass</code> | * <code>WarnClass</code> — название детектора/класса детекторов | ||
Имена полей также могут использоваться в формате, где первая буква в lowercase. | |||
Помимо использования полей, можно использовать вспомогательные функции для доступа к дополнительной информации: | |||
* <code>severity(item) string</code> — серьезность детектора (чекера) | |||
Пример: | |||
filter(markers, severity(#) == "Critical") | |||
'''Внимание:''' | |||
'''Внимание:''' использование в предикатах поля <code>Trace</code> может сказаться на скорости применения фильтра, т. к. загрузка большого числа трасс может занять время. | |||
=== Данные о разметке === | === Данные о разметке === | ||
Поддерживаются следующие функции для получения информации о | Поддерживаются следующие функции для получения информации о разметке: | ||
* <code>status(item) string</code> | * <code>status(item) string</code> — статус разметки текущего маркера. Пример: <code>filter(markers, status(#) == "Confirmed")</code> | ||
* <code>action(item) string</code> | * <code>action(item) string</code> — статус поля action текущего маркера. Пример: <code>filter(markers, action(#) == "Ignore")</code> | ||
* <code>mseverity(item) string</code> | * <code>mseverity(item) string</code> — статус поля severity текущего маркера (не путать с severity детектора). Пример: <code>filter(markers, mseverity(#) == "Critical")</code> | ||
* <code>triaged(item) bool</code> | * <code>triaged(item) bool</code> — возвращает true, если маркер имеет не дефолтную разметку. Пример: <code>filter(markers, triaged(#))</code> | ||
* <code>get_triaged_by(item) UserInfo</code> | * <code>get_triaged_by(item) UserInfo</code> — возвращает структуру с информацией о пользователе, кто произвел разметку | ||
Поля структуры <code>UserInfo</code>: | Поля структуры <code>UserInfo</code>: | ||
* <code>login: string</code> | * <code>login: string</code> — логин пользователя | ||
* <code>create_ts: Time (UTC)</code> | * <code>create_ts: Time (UTC)</code> — время разметки в UTC формате (RFC3339) | ||
=== Комментарии === | === Комментарии === | ||
Объекты типа <code>Comment</code> содержатся в поле <code>Comments</code> маркера. Объект имеет следующие поля: | Объекты типа <code>Comment</code> содержатся в поле <code>Comments</code> маркера. Объект имеет следующие поля: | ||
* <code>ID</code> | * <code>ID</code> — UUID комментария | ||
* <code>Text</code> | * <code>Text</code> — текст комментария | ||
* <code>CreatedBy</code> | * <code>CreatedBy</code> — имя пользователя, кто создал комментарий | ||
* <code>CreateTs</code> | * <code>CreateTs</code> — время создания комментария (объект типа <code>time.Time</code>) | ||
* <code>UpdateTs</code> | * <code>UpdateTs</code> — время обновления комментария (объект типа <code>time.Time</code>), может быть пустым | ||
* <code>UpdatedBy</code> | * <code>UpdatedBy</code> — имя пользователя, кто обновил комментарий | ||
=== Трассы === | === Трассы === | ||
Маркер может содержать трассу маркера в поле <code>Traces</code>. Трасса описывается следующими структурами: | Маркер может содержать трассу маркера в поле <code>Traces</code>. Трасса описывается следующими структурами: | ||
type Trace struct { | |||
Role string | Role string | ||
Locations []TraceEntry | Locations []TraceEntry | ||
| Line 77: | Line 84: | ||
Col uint32 | Col uint32 | ||
Info string | Info string | ||
} | } | ||
Имена полей могут использоваться в виде как описано выше, либо в формате | Доступ к полям объекта <code>Trace</code> может выполняться, используя правила языка <code>go-expr</code>, описанные ниже. | ||
Имена полей могут использоваться в виде как описано выше, либо в формате lowercase: <code>role, locations, file, line, col, info</code> | |||
Пример: | Пример: | ||
filter(markers, any(.Comments, .Text == "Test") && | |||
any(.Traces, any(.Locations, .Info == "Boolean expression has constant value")) | any(.Traces, any(.Locations, .Info == "Boolean expression has constant value")) | ||
) | ) | ||
=== Поля снимка === | === Поля снимка === | ||
Для доступа к полям снимка | Для доступа к полям снимка можно использовать переменную <code>snapshot</code>. Переменная имеет тип структуры со следующими полями | ||
struct { | |||
ID string | ID string | ||
Name string | Name string | ||
| Line 101: | Line 110: | ||
CreateTime time.Time | CreateTime time.Time | ||
SourcesAvailable bool | SourcesAvailable bool | ||
} | } | ||
Имена полей могут использоваться в виде, где первая буква в | Имена полей могут использоваться в виде, где первая буква в lowercase. | ||
Объекты в поле <code>Details</code> можно просмотреть нажав на <code>View JSON</code> | Объекты в поле <code>Details</code> можно просмотреть, нажав на кнопку <code>View JSON</code> в WebUI в поле <code>Snapshot Information</code>. | ||
Пример: | Пример: | ||
filter(markers, | |||
snapshot.buildObject == "5b634b75422bd554a8569cc10bfadc3aea77b73e" && | snapshot.buildObject == "5b634b75422bd554a8569cc10bfadc3aea77b73e" && | ||
.warnClass matches "DEREF" | .warnClass matches "DEREF" | ||
) | ) | ||
= Описание языка предикатов = | == Описание языка предикатов == | ||
Для написания предикатов используется язык | Для написания предикатов используется язык '''Expr'''. Детальное описание всех возможностей можно найти здесь: https://github.com/expr-lang/expr | ||
Далее описываются конструкции, наиболее подходящие для написания правил фильтрации. | Далее описываются конструкции, наиболее подходящие для написания правил фильтрации. | ||
== Литералы == | === Литералы === | ||
Comment /* */ or // | |||
Boolean true, false | Boolean true, false | ||
Integer 42, 0x2A, 0o52, 0b101010 | Integer 42, 0x2A, 0o52, 0b101010 | ||
| Line 125: | Line 134: | ||
Array [1, 2, 3] | Array [1, 2, 3] | ||
Map {a: 1, b: 2, c: 3} | Map {a: 1, b: 2, c: 3} | ||
Nil nil | Nil nil | ||
=== Строки === | === Строки === | ||
Строки могут быть в одинарных и двойных кавычках. Для эскейпа | Строки могут быть в одинарных и двойных кавычках. Для эскейпа используйте обратный слэш. | ||
Пример однострочного текста: | Пример однострочного текста: | ||
"Hello\nWorld" | |||
Пример многострочного текста: | Пример многострочного текста: | ||
`Hello | |||
World` | |||
В многострочном тексте escape-последовательности не поддерживаются. | В многострочном тексте escape-последовательности не поддерживаются. | ||
== Операторы == | === Операторы === | ||
Arithmetic: +, -, *, /, % (modulus), ^ or ** (exponent) | |||
Comparison: ==, !=, <, >, <=, >= | Comparison: ==, !=, <, >, <=, >= | ||
Logical: not or !, and or &&, or or || | Logical: not or !, and or &&, or or || | ||
| Line 147: | Line 158: | ||
Range .. | Range .. | ||
Slice [:] | Slice [:] | ||
Pipe | | Pipe | | ||
=== Операторы доступа к полю объекта === | === Операторы доступа к полю объекта === | ||
Можно использовать оператор точка <code>.</code> и оператор <code>[]</code>: | |||
<code>user.Name | <code>user.Name | ||
user["Name"]</code> | user["Name"]</code> | ||
| Line 159: | Line 170: | ||
"name" in {"name": "John", "age": 30}</code> | "name" in {"name": "John", "age": 30}</code> | ||
=== Optional chaining === | |||
Оператор <code>?.</code> может использоваться для доступа к полю структуры или элементу отображения (map) без необходимости проверки, является ли структура или отображение равными <code>nil</code>. Если структура или отображение имеют значение <code>nil</code>, результатом выражения будет <code>nil</code>. | Оператор <code>?.</code> может использоваться для доступа к полю структуры или элементу отображения (map) без необходимости проверки, является ли структура или отображение равными <code>nil</code>. Если структура или отображение имеют значение <code>nil</code>, результатом выражения будет <code>nil</code>. | ||
| Line 167: | Line 178: | ||
<code>author.User != nil ? author.User.Name : nil</code> | <code>author.User != nil ? author.User.Name : nil</code> | ||
=== Nil coalescing === | |||
Оператор <code>??</code> может использоваться для возврата левого операнда, если он не равен <code>nil</code>, в противном случае возвращается правый операнд. | Оператор <code>??</code> может использоваться для возврата левого операнда, если он не равен <code>nil</code>, в противном случае возвращается правый операнд. | ||
| Line 183: | Line 194: | ||
<code>split(lower(user.Name), " ")</code> | <code>split(lower(user.Name), " ")</code> | ||
== Предикаты == | === Предикаты === | ||
Предикат — это выражение. Предикаты можно использовать в функциях, таких как filter, all, any, one, none и других. | Предикат — это выражение. Предикаты можно использовать в функциях, таких как filter, all, any, one, none и других. | ||
<code>filter(0..9, {# % 2 == 0})</code> | <code>filter(0..9, {# % 2 == 0})</code> | ||
| Line 191: | Line 202: | ||
<code>filter(tweets, len(.Content) > 240)</code> | <code>filter(tweets, len(.Content) > 240)</code> | ||
== Операции над строками == | === Операции над строками === | ||
<code>trim(str[, chars]) | <code>trim(str[, chars]) | ||
trimPrefix(str, prefix) | trimPrefix(str, prefix) | ||
| Line 206: | Line 217: | ||
<code>str matches "^regex$"</code> | <code>str matches "^regex$"</code> | ||
== Функции времени == | === Функции времени === | ||
Поддерживаются Go типы для времени и интервалов (<code>time.Time</code>, <code>time.Duration</code>) time package. | Поддерживаются Go типы для времени и интервалов (<code>time.Time</code>, <code>time.Duration</code>) time package. | ||
| Line 221: | Line 232: | ||
date("2023-08-14 00:00:00", "2006-01-02 15:04:05", "Europe/Zurich")</code> | date("2023-08-14 00:00:00", "2006-01-02 15:04:05", "Europe/Zurich")</code> | ||
== Функции над массивами == | === Функции над массивами === | ||
* <code>all(array, predicate)</code> — все объекты должны удовлетворять предикату | |||
* <code>any(array, predicate)</code> — должен быть по крайней мере один объект, который удовлетворяет предикату | |||
* <code>one(array, predicate)</code> — должен быть только один объект, который удовлетворяет предикату | |||
* <code>none(array, predicate)</code> — ни один объект не должен удовлетворять предикату | |||
* <code>find(array, predicate)</code> — возвращает первый объект, который удовлетворяет предикату | |||
* <code>findLast(array, predicate)</code> — возвращает последний объект, который удовлетворяет предикату | |||
* <code>count(array[, predicate])</code> — возвращает число объектов, удовлетворяющих предикату | |||
* <code>first(array)</code> — первый объект из массива | |||
* <code>last(array)</code> — последний объект из массива | |||
Примеры: | Примеры: | ||
all(tweets, {.Size < 280}) | |||
any(tweets, {.Size > 280}) | |||
none(tweets, {.Size > 280}) | |||
find([1, 2, 3, 4], # > 2) == 3 | |||
findLast([1, 2, 3, 4], # > 2) == 4 | |||
count(users, .Age > 18) | |||
first([1, 2, 3]) == 1 | |||
last([1, 2, 3]) == 3 | |||
Revision as of 18:40, 2 December 2025
Advanced filters
Поле "Расширенный фильтр" в пользовательских фильтрах предназначено для фильтрации маркеров (предупреждений) по сложным предикатам.

Предикат может использовать:
- поля маркера, его трассы, разметки и комментариев
- информацию из контекста: имя проекта, ветки, снимка и т. п.
- атрибуты снимка, включая пользовательские атрибуты, заданные при импорте
- статусы разметки
- текст и атрибуты комментариев
Формат фильтра определяется следующим шаблоном:
filter(markers, <predicate expr>)
Выражение <predicate expr> определяет предикат. Объект markers содержит массив маркеров из контекста, функция filter фильтрует данный список по предикату. Таким образом, применение фильтра заключается в фильтрации списка маркеров по указанному предикату.
Список доступных полей
Поля маркера (предупреждения)
Comments— список комментариев маркера. Объект типа Comment (смотрите ниже)Details— информация, специфичная для анализатора. Ближайший аналог — fingerprint в SARIFFile— имя файлаFunction— имя функции, может быть mangled для С++ID— UUID маркераInvariant— инвариант маркера. Используется для автопереноса разметки между снимкамиLang— язык детектораLine— номер строки в файлеLocID— порядковый номер маркера относительно изначального отчета анализатораMTid— шаблон сообщенияMsg— текст сообщенияOrigFunc— 'человекочитаемое' имя функции. Может быть недоступноTags— список тегов (меток) маркераTool— модуль анализатора, ответственного за данный детекторTraces— список трасс маркера. Объект типа Trace (смотрите ниже)WarnClass— название детектора/класса детекторов
Имена полей также могут использоваться в формате, где первая буква в lowercase.
Помимо использования полей, можно использовать вспомогательные функции для доступа к дополнительной информации:
severity(item) string— серьезность детектора (чекера)
Пример:
filter(markers, severity(#) == "Critical")
Внимание: использование в предикатах поля Trace может сказаться на скорости применения фильтра, т. к. загрузка большого числа трасс может занять время.
Данные о разметке
Поддерживаются следующие функции для получения информации о разметке:
status(item) string— статус разметки текущего маркера. Пример:filter(markers, status(#) == "Confirmed")action(item) string— статус поля action текущего маркера. Пример:filter(markers, action(#) == "Ignore")mseverity(item) string— статус поля severity текущего маркера (не путать с severity детектора). Пример:filter(markers, mseverity(#) == "Critical")triaged(item) bool— возвращает true, если маркер имеет не дефолтную разметку. Пример:filter(markers, triaged(#))get_triaged_by(item) UserInfo— возвращает структуру с информацией о пользователе, кто произвел разметку
Поля структуры UserInfo:
login: string— логин пользователяcreate_ts: Time (UTC)— время разметки в UTC формате (RFC3339)
Комментарии
Объекты типа Comment содержатся в поле Comments маркера. Объект имеет следующие поля:
ID— UUID комментарияText— текст комментарияCreatedBy— имя пользователя, кто создал комментарийCreateTs— время создания комментария (объект типаtime.Time)UpdateTs— время обновления комментария (объект типаtime.Time), может быть пустымUpdatedBy— имя пользователя, кто обновил комментарий
Трассы
Маркер может содержать трассу маркера в поле Traces. Трасса описывается следующими структурами:
type Trace struct {
Role string
Locations []TraceEntry
}
type TraceEntry struct {
File string
Line uint32
Col uint32
Info string
}
Доступ к полям объекта Trace может выполняться, используя правила языка go-expr, описанные ниже.
Имена полей могут использоваться в виде как описано выше, либо в формате lowercase: role, locations, file, line, col, info
Пример:
filter(markers, any(.Comments, .Text == "Test") && any(.Traces, any(.Locations, .Info == "Boolean expression has constant value")) )
Поля снимка
Для доступа к полям снимка можно использовать переменную snapshot. Переменная имеет тип структуры со следующими полями
struct {
ID string
Name string
SerialID uint32
BuildObject string
ResultsObject string
ImportTime time.Time
CreatedBy string
CreatedByID string
Details map[string]any
CreateTime time.Time
SourcesAvailable bool
}
Имена полей могут использоваться в виде, где первая буква в lowercase.
Объекты в поле Details можно просмотреть, нажав на кнопку View JSON в WebUI в поле Snapshot Information.
Пример:
filter(markers, snapshot.buildObject == "5b634b75422bd554a8569cc10bfadc3aea77b73e" && .warnClass matches "DEREF" )
Описание языка предикатов
Для написания предикатов используется язык Expr. Детальное описание всех возможностей можно найти здесь: https://github.com/expr-lang/expr
Далее описываются конструкции, наиболее подходящие для написания правил фильтрации.
Литералы
Comment /* */ or //
Boolean true, false
Integer 42, 0x2A, 0o52, 0b101010
Float 0.5, .5
String "foo", 'bar'
Array [1, 2, 3]
Map {a: 1, b: 2, c: 3}
Nil nil
Строки
Строки могут быть в одинарных и двойных кавычках. Для эскейпа используйте обратный слэш.
Пример однострочного текста:
"Hello\nWorld"
Пример многострочного текста:
`Hello World`
В многострочном тексте escape-последовательности не поддерживаются.
Операторы
Arithmetic: +, -, *, /, % (modulus), ^ or ** (exponent)
Comparison: ==, !=, <, >, <=, >=
Logical: not or !, and or &&, or or ||
Conditional: ?: (ternary), ?? (nil coalescing), if {} else {} (multiline)
Membership: [], ., ?., in
String: + (concatenation), contains, startsWith, endsWith
Regex: matches
Range ..
Slice [:]
Pipe |
Операторы доступа к полю объекта
Можно использовать оператор точка . и оператор []:
user.Name
user["Name"]
Оператор in
Оператор in для проверки наличия объекта в массиве или мэпе:
"John" in ["John", "Jane"]
"name" in {"name": "John", "age": 30}
Optional chaining
Оператор ?. может использоваться для доступа к полю структуры или элементу отображения (map) без необходимости проверки, является ли структура или отображение равными nil. Если структура или отображение имеют значение nil, результатом выражения будет nil.
Пример вида:
author.User?.Name
значит тоже самое, что:
author.User != nil ? author.User.Name : nil
Nil coalescing
Оператор ?? может использоваться для возврата левого операнда, если он не равен nil, в противном случае возвращается правый операнд.
Пример вида:
author.User?.Name ?? "Anonymous"
значит тоже самое, что:
author.User != nil ? author.User.Name : "Anonymous"
Оператор конвейера
Оператор конвейера | может использоваться для передачи результата выражения левого операнда в качестве первого аргумента выражения правого операнда.
Пример вида:
user.Name | lower() | split(" ")
значит тоже самое, что:
split(lower(user.Name), " ")
Предикаты
Предикат — это выражение. Предикаты можно использовать в функциях, таких как filter, all, any, one, none и других.
filter(0..9, {# % 2 == 0})
filter(tweets, {len(.Content) > 240})
Скобки можно опускать { }:
filter(tweets, len(.Content) > 240)
Операции над строками
trim(str[, chars])
trimPrefix(str, prefix)
trimSuffix(str, suffix)
upper(str)
lower(str)
indexOf(str, substring)
lastIndexOf(str, substring)
hasPrefix(str, prefix)
hasSuffix(str, suffix)
Так же есть оператор matches для поиска регулярного выражения в строке:
str matches "regular expression"
Для сопоставления целой строки с регулярным выражением следует использовать вариант:
str matches "^regex$"
Функции времени
Поддерживаются Go типы для времени и интервалов (time.Time, time.Duration) time package.
Можно использовать операции сложения и вычитания над объектами с типом time.Time.
createdAt - now()
createdAt + duration("1h")
createdAt > now() - duration("1h")
date("2023-08-14")
date("15:04:05")
date("2023-08-14T00:00:00Z")
date("2023-08-14 00:00:00", "2006-01-02 15:04:05", "Europe/Zurich")
Функции над массивами
all(array, predicate)— все объекты должны удовлетворять предикатуany(array, predicate)— должен быть по крайней мере один объект, который удовлетворяет предикатуone(array, predicate)— должен быть только один объект, который удовлетворяет предикатуnone(array, predicate)— ни один объект не должен удовлетворять предикатуfind(array, predicate)— возвращает первый объект, который удовлетворяет предикатуfindLast(array, predicate)— возвращает последний объект, который удовлетворяет предикатуcount(array[, predicate])— возвращает число объектов, удовлетворяющих предикатуfirst(array)— первый объект из массиваlast(array)— последний объект из массива
Примеры:
all(tweets, {.Size < 280})
any(tweets, {.Size > 280})
none(tweets, {.Size > 280})
find([1, 2, 3, 4], # > 2) == 3
findLast([1, 2, 3, 4], # > 2) == 4
count(users, .Age > 18)
first([1, 2, 3]) == 1
last([1, 2, 3]) == 3