문서API 참조
Documentation

규칙 구성

Sandfly가 무엇을 탐지할지 정의하는 것이 규칙입니다. 규칙은 expr 언어로 작성된 불리언 표현식(따라서 반드시 true 또는 false 값을 반환해야 함)입니다. Sandfly는 rules 배열에 여러 규칙을 포함할 수 있으며, rule_op 속성 값에 따라 "and" 또는 "or" 논리로 결합됩니다. 결합된 규칙의 평가 결과가 true이면 해당 항목에 대해 Sandfly가 경고를 생성합니다.

Expr 언어 정의


리터럴

NameExamples
Comment/* */ or //
Booleantrue, false
Integer42, 0x2A, 0o52, 0b101010
Float0.5, .5
String"foo", 'bar'
Array[1, 2, 3]
Map{a: 1, b: 2, c: 3}
Nilnil

문자열

문자열은 작은따옴표 또는 큰따옴표로 둘러쌀 수 있습니다. 문자열에는 줄바꿈을 위한 \n, 탭을 위한 \t, 유니코드 코드 포인트를 위한 \uXXXX 같은 이스케이프 시퀀스를 포함할 수 있습니다.

"Hello\nWorld"

여러 줄 문자열은 백틱(backtick)을 사용합니다:

`Hello World`

백틱 문자열은 원시 문자열이므로 이스케이프 시퀀스를 지원하지 않습니다.

연산자

NameType(s)
Arithmetic+, -, *, /, % (modulus), ^ or ** (exponent)
Comparison==, !=, <, >, <=, >=
Logicalnot or !, and or &&, or or ||
Conditional?: (ternary), ??(nil coalescing), if else (multiline)
Membership[], ., ?., in
String+ (concatenation), contains, startsWith, endsWith
Regexmatches
Range..
Slice[:]
Pipe|

멤버십 연산자

구조체의 필드와 맵의 항목은 . 연산자 또는 [] 연산자로 접근할 수 있습니다. 다음 두 표현식은 같습니다:

user.Name user["Name"]

배열과 슬라이스의 요소는 [] 연산자로 접근합니다. 음수 인덱스를 지원하며, -1은 마지막 요소를 의미합니다.

array[0] // first element array[-1] // last element

in 연산자는 항목이 배열 또는 맵에 존재하는지 확인할 때 사용합니다.

"John" in ["John", "Jane"] "name" in {"name": "John", "age": 30}

옵셔널 체이닝

?. 연산자는 구조체나 맵이 nil인지 확인하지 않고도 필드나 항목에 접근할 수 있게 해줍니다. 구조체나 맵이 nil이면 해당 표현식의 결과는 nil입니다.

author.User?.Name

다음과 동일합니다:

author.User != nil ? author.User.Name : nil

Nil 병합

?? 연산자는 좌변이 nil이 아니면 좌변을, 그렇지 않으면 우변을 반환합니다.

author.User?.Name ?? "Anonymous"

다음과 동일합니다:

author.User != nil ? author.User.Name : "Anonymous"

슬라이스 연산자

슬라이스 연산자 [:]는 배열의 일부 구간에 접근할 때 사용합니다.

예를 들어 변수 array[1, 2, 3, 4, 5]인 경우:

array[1:4] == [2, 3, 4] array[1:-1] == [2, 3, 4] array[:3] == [1, 2, 3] array[3:] == [4, 5] array[:] == array

파이프 연산자

파이프 연산자 | 는 좌변 표현식의 결과를 우변 표현식의 첫 번째 인자로 전달하는 데 사용할 수 있습니다.

user.Name | lower() | split(" ")

다음과 동일합니다:

split(lower(user.Name), " ")

범위 연산자

범위 연산자 .. 는 정수 범위를 생성할 때 사용할 수 있습니다.

1..3 == [1, 2, 3]

변수

변수는 let 키워드로 선언할 수 있습니다. 변수명은 문자 또는 밑줄로 시작해야 하며, 문자·숫자·밑줄을 포함할 수 있습니다. 변수가 선언된 이후에는 표현식에서 사용할 수 있습니다.

let x = 42; x * 2

세미콜론으로 구분된 여러 개의 let 문으로 변수 여러 개를 선언할 수 있습니다.

let x = 42; let y = 2; x \* y

아래는 파이프 연산자를 사용한 변수 예시입니다:

let name = user.Name | lower() | split(" "); "Hello, " + name[0] + "!"

$env

$env 변수는 표현식에 전달된 모든 변수를 담고 있는 맵입니다.

foo.Name == $env["foo"].Name $env["var with spaces"]

$env는 모든 변수를 담고 있는 전역 변수라고 생각하면 됩니다.

변수가 정의되어 있는지 확인할 때 $env를 사용할 수 있습니다:

'foo' in $env

프레디케이트

프레디케이트는 하나의 표현식입니다. 프레디케이트는 filter, all, any, one, none 등의 함수에서 사용할 수 있습니다. 예를 들어, 다음 표현식은 0부터 9까지의 새 배열을 만들고 짝수만 필터링합니다:

filter(0..9, {# % 2 == 0})

배열의 항목이 구조체나 맵인 경우, # 기호를 생략하고 필드에 접근할 수 있습니다(#.Value.Value).

filter(tweets, {len(.Content) > 240})

중괄호 { }는 생략할 수 있습니다:

filter(tweets, len(.Content) > 240)
👍

팁: 중첩 프레디케이트에서 바깥 변수를 참조하려면 변수 사용.

filter(posts, { let post = #; any(.Comments, .Author == post.Author) })

문자열 함수

trim(str[, chars])

문자열 str 양 끝의 공백을 제거합니다. 선택 인수인 chars가 주어지면 제거할 문자 집합을 지정하는 문자열입니다.

trim(" Hello ") == "Hello" trim("__Hello__", "_") == "Hello"

trimPrefix(str, prefix)

문자열 str이 지정된 접두사로 시작하면 그 접두사를 제거합니다.

trimPrefix("HelloWorld", "Hello") == "World"

trimSuffix(str, suffix)

문자열 str이 지정된 접미사로 끝나면 그 접미사를 제거합니다.

trimSuffix("HelloWorld", "World") == "Hello"

upper(str)

문자열 str의 모든 문자를 대문자로 변환합니다.

upper("hello") == "HELLO"

lower(str)

문자열 str의 모든 문자를 소문자로 변환합니다.

lower("HELLO") == "hello"

split(str, delimiter[, n])

구분자가 나타나는 위치마다 문자열 str을 분리하여 부분 문자열 배열을 반환합니다.

split("apple,orange,grape", ",") == ["apple", "orange", "grape"] split("apple,orange,grape", ",", 2) == ["apple", "orange,grape"]

splitAfter(str, delimiter[, n])

구분자가 나타난 직후마다 문자열 str을 분리합니다.

splitAfter("apple,orange,grape", ",") == ["apple,", "orange,", "grape"] splitAfter("apple,orange,grape", ",", 2) == ["apple,", "orange,grape"]

replace(str, old, new)

문자열 str에서 old가 나타나는 모든 위치를 new로 대체합니다.

replace("Hello World", "World", "Universe") == "Hello Universe"

repeat(str, n)

문자열 strn회 반복합니다.

repeat("Hi", 3) == "HiHiHi"

indexOf(str, substring)

부분 문자열이 처음 나타나는 인덱스를 반환하며, 없으면 -1을 반환합니다.

indexOf("apple pie", "pie") == 6

lastIndexOf(str, substring)

부분 문자열이 마지막으로 나타나는 인덱스를 반환하며, 없으면 -1을 반환합니다.

lastIndexOf("apple pie apple", "apple") == 10

hasPrefix(str, prefix)

문자열이 주어진 접두사로 시작하면 true를 반환합니다.

hasPrefix("HelloWorld", "Hello") == true

hasSuffix(str, suffix)

문자열이 주어진 접미사로 끝나면 true를 반환합니다.

hasSuffix("HelloWorld", "World") == true

날짜 함수

Expr는 Go의 time 패키지를 기본 지원합니다. 두 날짜를 뺄셈하여 그 사이의 지속 시간(duration)을 구할 수 있습니다:

createdAt - now()

날짜에 지속 시간을 더할 수도 있습니다:

createdAt + duration("1h")

날짜 비교도 가능합니다:

createdAt > now() - duration("1h")

now()

현재 날짜를 time.Time 값으로 반환합니다.

now().Year() == 2024

duration(str)

주어진 문자열 strtime.Duration 값을 반환합니다.

유효한 시간 단위는 "ns", "us"(또는 "µs"), "ms", "s", "m", "h" 입니다.

duration("1h").Seconds() == 3600

date(str[, format[, timezone]])

주어진 문자열 str을 날짜 표현으로 변환합니다.

선택 인수인 format이 주어지면 날짜 형식을 지정하는 문자열입니다. 형식 문자열은 표준 Go time 패키지와 동일한 규칙을 사용합니다.

선택 인수인 timezone이 주어지면 날짜의 시간대를 지정하는 문자열입니다.

format 인수가 없으면, 인수 v는 다음 형식 중 하나여야 합니다:

  • 2006-01-02
  • 15:04:05
  • 2006-01-02 15:04:05
  • RFC3339
  • RFC822
  • RFC850
  • RFC1123
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")

date에서 사용할 수 있는 메서드:

  • Year() - 연도 반환
  • Month() - 월 반환(1부터 시작)
  • Day() - 일(일자) 반환
  • Hour() - 시 반환
  • Minute() - 분 반환
  • Second() - 초 반환
  • Weekday() - 요일 반환
  • YearDay() - 연중 일수 반환
  • 그 외 추가 메서드가 있습니다.
date("2023-08-14").Year() == 2023

timezone(str)

주어진 문자열 str의 시간대를 반환합니다. 사용 가능한 시간대 목록은 여기에서 확인할 수 있습니다.

timezone("Europe/Zurich") timezone("UTC")

다른 시간대로 변환하려면 In() 메서드를 사용하세요:

date("2023-08-14 00:00:00").In(timezone("Europe/Zurich"))

숫자 함수

max(n1, n2)

두 수 n1n2 중 더 큰 값을 반환합니다.

max(5, 7) == 7

min(n1, n2)

두 수 n1n2 중 더 작은 값을 반환합니다.

min(5, 7) == 5

abs(n)

숫자의 절대값을 반환합니다.

abs(-5) == 5

ceil(n)

x보다 크거나 같은 최소의 정수 값을 반환합니다.

ceil(1.5) == 2.0

floor(n)

x보다 작거나 같은 최대의 정수 값을 반환합니다.

floor(1.5) == 1.0

round(n)

가장 가까운 정수로 반올림하며, .5는 0에서 멀어지는 방향으로 반올림합니다.

round(1.5) == 2.0

배열 함수

all(array, predicate)

모든 요소가 프레디케이트를 만족하면 true를 반환합니다. 배열이 비어 있으면 true를 반환합니다.

all(tweets, {.Size < 280})

any(array, predicate)

하나라도 요소가 프레디케이트를 만족하면 true를 반환합니다. 배열이 비어 있으면 false를 반환합니다.

any(tweets, {.Size > 280})

one(array, predicate)

정확히 하나의 요소만 프레디케이트를 만족하면 true를 반환합니다. 배열이 비어 있으면 false를 반환합니다.

one(participants, {.Winner})

none(array, predicate)

모든 요소가 프레디케이트를 만족하지 않으면 true를 반환합니다. 배열이 비어 있으면 true를 반환합니다.

none(tweets, {.Size > 280})

map(array, predicate)

배열의 각 요소에 프레디케이트를 적용해 새로운 배열을 반환합니다.

map(tweets, {.Size})

filter(array, predicate)

프레디케이트로 배열의 요소를 필터링하여 새로운 배열을 반환합니다.

filter(users, .Name startsWith "J")

find(array, predicate)

프레디케이트를 만족하는 첫 번째 요소를 찾습니다.

find([1, 2, 3, 4], # > 2) == 3

findIndex(array, predicate)

프레디케이트를 만족하는 첫 번째 요소의 인덱스를 찾습니다.

findIndex([1, 2, 3, 4], # > 2) == 2

findLast(array, predicate)

프레디케이트를 만족하는 마지막 요소를 찾습니다.

findLast([1, 2, 3, 4], # > 2) == 4

findLastIndex(array, predicate)

프레디케이트를 만족하는 마지막 요소의 인덱스를 찾습니다.

findLastIndex([1, 2, 3, 4], # > 2) == 3

groupBy(array, predicate)

프레디케이트 결과에 따라 배열 요소를 그룹화합니다.

groupBy(users, .Age)

count(array[, predicate])

프레디케이트를 만족하는 요소의 개수를 반환합니다.

count(users, .Age > 18)

다음과 동일합니다:

len(filter(users, .Age > 18))

프레디케이트가 주어지지 않으면, 배열에서 true 값의 개수를 반환합니다.

count([true, false, true]) == 2

concat(array1, array2[, ...])

두 개 이상의 배열을 이어 붙입니다.

concat([1, 2], [3, 4]) == [1, 2, 3, 4]

flatten(array)

주어진 배열을 1차원 배열로 평탄화합니다.

flatten([1, 2, [3, 4]]) == [1, 2, 3, 4]

uniq(array)

배열에서 중복을 제거합니다.

uniq([1, 2, 3, 2, 1]) == [1, 2, 3]

join(array[, delimiter])

문자열 배열을 지정한 구분자로 합쳐 하나의 문자열로 만듭니다. 구분자가 없으면 빈 문자열을 사용합니다.

join(["apple", "orange", "grape"], ",") == "apple,orange,grape" join(["apple", "orange", "grape"]) == "appleorangegrape"

reduce(array, predicate[, initialValue])

배열 각 요소에 프레디케이트를 적용해 단일 값으로 축약합니다. 선택 인수 initialValue로 누산기의 초기값을 지정할 수 있습니다. initialValue가 없으면 배열의 첫 요소가 초기값으로 사용됩니다.

프레디케이트 내부에서 다음 변수를 사용할 수 있습니다:

  • # - the current element
  • #acc - the accumulator
  • #index - the index of the current element
reduce(1..9, #acc + #) reduce(1..9, #acc + #, 0)

sum(array[, predicate])

배열의 모든 수를 합한 값을 반환합니다.

sum([1, 2, 3]) == 6

선택 인수 predicate가 주어지면, 합산 전에 각 요소에 적용할 프레디케이트입니다.

sum(accounts, .Balance)

다음과 동일합니다:

reduce(accounts, #acc + .Balance, 0) // or sum(map(accounts, .Balance))

mean(array)

배열의 모든 수의 평균을 반환합니다.

mean([1, 2, 3]) == 2.0

median(array)

배열의 모든 수의 중앙값을 반환합니다.

median([1, 2, 3]) == 2.0

first(array)

배열의 첫 번째 요소를 반환합니다. 배열이 비어 있으면 nil을 반환합니다.

first([1, 2, 3]) == 1

last(array)

배열의 마지막 요소를 반환합니다. 배열이 비어 있으면 nil을 반환합니다.

last([1, 2, 3]) == 3

take(array, n)

배열에서 앞쪽 n개 요소를 반환합니다. 요소 수가 n보다 적으면 전체 배열을 반환합니다.

take([1, 2, 3, 4], 2) == [1, 2]

reverse(array)

배열을 뒤집은 새로운 복사본을 반환합니다.

reverse([3, 1, 4]) == [4, 1, 3] reverse(reverse([3, 1, 4])) == [3, 1, 4]

sort(array[, order])

배열을 오름차순으로 정렬합니다. 선택 인수 order로 정렬 순서를 지정할 수 있습니다: asc 또는 desc.

sort([3, 1, 4]) == [1, 3, 4] sort([3, 1, 4], "desc") == [4, 3, 1]

sortBy(array[, predicate, order])

맵 배열을 특정 키 기준으로 오름차순 정렬합니다. 선택 인수 order로 정렬 순서를 지정할 수 있습니다: asc 또는 desc.

sortBy(users, "Age") sortBy(users, "Age", "desc")

맵 함수

keys(map)

맵의 키를 담은 배열을 반환합니다.

keys({"name": "John", "age": 30}) == ["name", "age"]

values(map)

맵의 값을 담은 배열을 반환합니다.

values({"name": "John", "age": 30}) == ["John", 30]

형 변환 함수

type(v)

주어진 값 v의 타입을 반환합니다.

반환 가능 타입은 다음과 같습니다:

  • nil
  • bool
  • int
  • uint
  • float
  • string
  • array
  • map

명명된 타입 및 구조체의 경우 타입 이름을 반환합니다.

type(42) == "int" type("hello") == "string" type(now()) == "time.Time"

int(v)

숫자 또는 문자열의 정수 값을 반환합니다.

int("123") == 123

float(v)

숫자 또는 문자열의 부동소수점 값을 반환합니다.

float("123.45") == 123.45

string(v)

주어진 값 v을 문자열 표현으로 변환합니다.

string(123) == "123"

toJSON(v)

주어진 값 v을 JSON 문자열로 변환합니다.

toJSON({"name": "John", "age": 30})

fromJSON(v)

주어진 JSON 문자열 v를 파싱하여 해당 값을 반환합니다.

fromJSON('{"name": "John", "age": 30}')

toBase64(v)

문자열 v를 Base64 형식으로 인코딩합니다.

toBase64("Hello World") == "SGVsbG8gV29ybGQ="

fromBase64(v)

Base64로 인코딩된 문자열 v를 원래 문자열로 디코딩합니다.

fromBase64("SGVsbG8gV29ybGQ=") == "Hello World"

toPairs(map)

맵을 키-값 쌍의 배열로 변환합니다.

toPairs({"name": "John", "age": 30}) == \[["name", "John"], ["age", 30]]

fromPairs(array)

키-값 쌍의 배열을 맵으로 변환합니다.

fromPairs(\[["name", "John"], ["age", 30]]) == {"name": "John", "age": 30}

기타 함수

len(v)

배열, 맵 또는 문자열의 길이를 반환합니다.

len([1, 2, 3]) == 3 len({"name": "John", "age": 30}) == 2 len("Hello") == 5

get(v, index)

배열 또는 맵 v에서 지정 인덱스의 요소를 가져옵니다. 인덱스가 범위를 벗어나거나 키가 없으면 nil을 반환합니다.

get([1, 2, 3], 1) == 2 get({"name": "John", "age": 30}, "name") == "John"

비트 연산 함수

bitand(int, int)

비트 AND 연산의 결과 값을 반환합니다.

bitand(0b1010, 0b1100) == 0b1000

bitor(int, int)

비트 OR 연산의 결과 값을 반환합니다.

bitor(0b1010, 0b1100) == 0b1110

bitxor(int, int)

비트 XOR 연산의 결과 값을 반환합니다.

bitxor(0b1010, 0b1100) == 0b110

bitnand(int, int)

비트 AND NOT 연산의 결과 값을 반환합니다.

bitnand(0b1010, 0b1100) == 0b10

bitnot(int)

비트 NOT 연산의 결과 값을 반환합니다.

bitnot(0b1010) == -0b1011

bitshl(int, int)

왼쪽 시프트 연산의 결과 값을 반환합니다.

bitshl(0b101101, 2) == 0b10110100

bitshr(int, int)

오른쪽 시프트 연산의 결과 값을 반환합니다.

bitshr(0b101101, 2) == 0b1011

bitushr(int, int)

부호 없는 오른쪽 시프트 연산의 결과 값을 반환합니다.

bitushr(-0b101, 2) == 4611686018427387902

이 페이지가 도움이 되었나요?