コンテンツにスキップ

カスタムパーサー構文🔗

重要

Taegis XDRカスタムパーサーでサポートされている正規表現の構文は、Golangバリアントです。

ステートメント🔗

!SAMPLE=...🔗

サンプルメッセージです。=の右側にあるすべての内容が、改行までリテラルとして解釈されます。このフィールドは任意ですが、強く推奨されます。

!SCHEMA=...🔗

このメッセージタイプのスキーマを指定します。例:scwx.nidsscwx.netflowscwx.auth。指定しない場合は、親または最も近い先祖のスキーマが使用されます。

!CONFIRMWITH🔗

PATTERN または EXPRESSION のいずれかです。!CONFIRMSTRING と連携して、このパーサーがメッセージに一致するかどうかを判定します。PATTERN の場合、CONFIRMSTRINGは正規表現パターンです。EXPRESSION の場合、CONFIRMSTRINGはTrue/Falseを評価する式です。

!CONFIRMSTRING=🔗

!CONFIRMWITH を参照してください。

!DISABLED=🔗

このパーサーを無効化します。パーサーはランタイムカタログから完全に削除されます。まだメッセージの処理方法が分からないが、その存在を最小限のドキュメントとして記録したい場合に便利です。

!IMPORT=🔗

他のパーサーを現在の行にインポートします。変数はインポート元とインポート先のパーサー間で共有されます。これにより、パーサーコードの繰り返し行を1か所にまとめることができます。

!IMPORTONLY🔗

このパーサーが !IMPORT 経由でのみインポート用であることを示します。極めて稀な例外を除き、すべてのインポートされるパーサーは !IMPORTONLY であるべきです。このフラグを設定すると、多くのバリデーションルール(例:親パーサー不要、CONFIRMWITH/CONFIRMSTRING不要など)が免除されます。

!TRIMALLOFF🔗

すべてのパーサーで TRIM_ALL() を実行するデフォルト動作を無効化します。場合によっては、TRIM_ALL() が先頭や末尾の波括弧({}[])を削除してしまい、Jsonフィールドのデータが不正確になることがあります。

!SANITIZEALLOFF🔗

すべてのパーサーで SANITIZE_ALL() を実行するデフォルト動作を無効化します。

正規表現キャプチャグループ🔗

キャプチャグループは、非構造化ログメッセージまたはその一部から値を抽出するために使用できます。

キャプチャグループの構文は {captureVariable} = {sourceString}|({regex pattern}) です。マッチした結果はリストに格納され、captureVariableと配列の値で参照できます(例:captureVariable[1])。

また、{captureVariable} = {sourceString}|(?P<group_name>{regex pattern}) のように名前付きでキャプチャすることもできます。結果は captureVariable とグループ名で参照できます(例:captureVariable["group_name"])。

🔗

# The pattern is read unescaped to the end of the line.

jsonMatch = originalData$|(\{.*})$

# To find patterns such as an IP address

# originalData = Dec 10 16:49:10 10.10.70.10 Dec 10 10:49:10 dddd-aaabbb-01 dddd-aaabbb-01

queryCapture = originalData$|\s\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}\s

# queryCapture = 10.10.70.10

# To capture a value after a field name

# message = Source Network Address: 10.17.2.186   Source Port:  54692

srcIp = message|Source Network Address:\s+(\S+)\s+

# srcIp = 10.17.2.186

# An example where the '%' character isn't scaped as in Golang regex

# message = %AAA-6-RADIUS_IN_GLOBAL_LIST: radius_db.c:481 RADIUS ACCT

topLevel = message|\s+%(\w+)-(\w+-)?(\d+)-(\w+):\s+(.+)

part = topLevel[1]

# part = AAA

# Named capture group example

# message = Aug 21 12:12:20 10.194.72.254 1 1566000000.000000000 IDOFDEVICE flows src=192.168.0.5 dst=192.168.0.255 mac=DE:ED:BE:EF:AB:AB protocol=udp sport=49154 dport=1128 pattern: deny (src 192.168.0.0/24)

partA = message|^(?P<prefix>0|1)\s+(?P<timestamp>\d+\.\d+)\s+(?P<idofdevice>\S+)\s+(?P<logtype>ip_flow|events|airmarshal_events|flows|security_event|ids-alerts|urls|.*firewall)\s+(?P<remainder>.*)

timestamp = partA["timestamp"]
device = partA["idofdevice"]
logtype = partA["logtype"]

# timestamp = 1566000000.000000000

# device = IDOFDEVICE

# logtype = flows

インデックスとメンバーアクセス🔗

値がキャプチャされた後(正規表現、SPLIT()JSON() など)、[index] 演算子を使って個々の要素を参照できます。この演算子は多態的で、インデックスされる値の型によって動作が異なります。

左辺 インデックスタイプ 戻り値 範囲外/未存在
LIST 数値 0始まりのインデックスの要素 NULL
OBJECT (map) 文字列 指定キーの値 NULL
正規表現マッチ 数値 指定インデックスのキャプチャグループ。[0] は全体、[1] は最初のグループ エラー(範囲外)
正規表現マッチ 文字列 (?P<name>...) の名前付きキャプチャグループ エラー(名前なし)
JSON JSONPath文字列 JSONPathに一致する要素 NULL

注意

数値と文字列はインデックスとして互換性がありません。リスト要素や位置指定の正規表現グループには数値を、オブジェクトキーや名前付き正規表現グループ、JSONPath式には文字列を使ってください。

正規表現マッチのインデックス🔗

キャプチャグループはパイプ構文 {var} = {source}|({regex}) で作成されます。パイプは source に対して正規表現を実行し、正規表現マッチ値を生成し、それをキャプチャグループ番号でインデックスします。

# message = "May 17 12:00:00 host login src=192.168.1.10 user=alice"

match = message|src=(\S+)\s+user=(\S+)

fullMatch = match[0]
# fullMatch: "src=192.168.1.10 user=alice"

srcIp = match[1]
# srcIp: "192.168.1.10"

userName = match[2]
# userName: "alice"

名前付きキャプチャグループ🔗

Golangの (?P<name>...) 構文を使ってグループに名前を付け、文字列でインデックスします。

parts = message|^(?P<level>\w+):\s+(?P<msg>.+)$
level = parts["level"]
msg   = parts["msg"]

リストのインデックス🔗

リストは SPLIT() などの関数で生成され、0始まりの数値インデックスでアクセスします。リストの末尾を超えて読み込むとエラーではなく NULL を返すため、スロットがない場合に動作が変わる場合は IF でガードしてください。

parts = SPLIT("a,b,c,d", ",")
first = parts[0]    # "a"
third = parts[2]    # "c"
miss  = parts[99]   # NULL

オブジェクトのインデックス🔗

SPLIT_NAME_VALUES() などの関数で返されるオブジェクト(キー/値マップ)は、文字列キーでアクセスします。キーが存在しない場合は NULL を返します。

dict = SPLIT_NAME_VALUES("user=alice,role=admin", ",", "=", "\\")
user = dict["user"]    # "alice"
miss = dict["email"]   # NULL

JSONのJSONPathによるインデックス🔗

JSON() の値は JSONPath 式を文字列で指定してインデックスします。

data = "{\"user\":{\"name\":\"alice\",\"id\":42}}"
obj  = JSON(data)
name = obj["$.user.name"]    # "alice"
miss = obj["$.user.email"]   # NULL

ワイルドカードの構造保持フラグ🔗

JSONPathでワイルドカード(*)を使ってリストを横断する場合、デフォルトでは要求されたフィールドがないスロットは除外されます。JSONPathの末尾に |preserve_structure を付けると、各スロットごとに1つのエントリが保持され、フィールドがない位置には NULL が入ります。入力内の他の配列と位置合わせが必要な場合に便利です。

data = "{\"items\":[{\"id\":1,\"tag\":\"a\"},{\"id\":2},{\"id\":3,\"tag\":\"c\"}]}"
json = JSON(data)

tagsCompact = json["$.items.*.tag"]
# tagsCompact: ["a", "c"]

tagsAligned = json["$.items.*.tag|preserve_structure"]
# tagsAligned: ["a", NULL, "c"]

関数🔗

SPLIT(data, delimiter, makeGreedy)🔗

datadelimiter で区切ってトークンに分割します。オプションの makeGreedy"true" の場合、データ 0,,2 をデリミタ , で分割すると [0,2] となり、[0,'',2] にはなりません。

🔗

data = "aaa,bbb,ccc,eee"
values1 = SPLIT(data, ",", FALSE)
OUTPUT1$ = values1[3]

#OUTPUT1$: eee (String)
data = "aaa,bbb,ccc,,eee"
values1 = SPLIT(data, ",", FALSE)
values2 = SPLIT(data, ",", TRUE)
OUTPUT1$ = values1[3]
OUTPUT2$ = values2[3]

#OUTPUT1$: NULL (null)
#OUTPUT2$: eee (String)

SPLIT_NAME_VALUES(data, delimiter, separator, quoteChar)🔗

data を、delimiter でペアを区切り、separator で名前と値を分ける名前/値ペアのコレクションに分割します。quotechar は値をクォートする文字を指定します。

🔗

data = "User: Unknown, InitiatorPackets: 2, ResponderPackets: 1, InitiatorBytes: 120, ResponderBytes: 66"
dict = SPLIT_NAME_VALUES(data, ",", ":", "\\")
OUTPUT$ = dict["InitiatorBytes"]

# OUTPUT$: 120 (String)

JSON(data)🔗

data をjsonオブジェクトに変換し、角括弧内にjson pathを指定してアクセスできます。詳細は https://goessner.net/articles/JsonPath/ および https://github.com/ohler55/ojg を参照してください。

🔗

data= "{ \"store\": { \"book\": [ { \"category\": \"reference\", \"author\": \"Nigel Rees\", \"title\": \"Sayings of the Century\", \"price\": 8.95 }, { \"category\": \"fiction\", \"author\": \"Evelyn Waugh\", \"title\": \"Sword of Honour\", \"price\": 12.99 }, { \"category\": \"fiction\", \"author\": \"Herman Melville\", \"title\": \"Moby Dick\", \"isbn\": \"0-553-21311-3\", \"price\": 8.99 }, { \"category\": \"fiction\", \"author\": \"J.R. R. Tolkien\", \"title\": \"The Lord of the Rings\", \"isbn\": \"0-395-19395-8\", \"price\": 22.99 } ], \"bicycle\": { \"color\": \"red\", \"price\": 19.95 } } }"
json= JSON(data)
OUTPUT$ = json["$.store.book[*].author"]

# OUTPUT$: "Nigel Rees","Evelyn Waugh","Herman Melville","J. R. R. Tolkien" (String)

ドットを含むJSONキーの利用例:

data= "{ \"store\": { \"book\": [ { \"id.category\": \"reference\" } ] } }"
json= JSON(data)
OUTPUT$ = json["$.store.book[0][\"id.category\"]"]

# OUTPUT$: reference(String)

CEF(data)🔗

data をCEF形式のメッセージとして解析します。ヘッダーフィールドは整数で、名前付きフィールドは名前でアクセスできます。

🔗

!SAMPLE=Nov 6 07:49:03 10.42.0.1 %helloWorld: CEF:0|Check Point|VPN-1 & FireWall-1|Check Point|Log|Address spoofing|Unknown|act=Drop cs3Label=Protection Type cs3=IPS

values = CEF(originalData$)
OUTPUT1$= values[2]
OUTPUT2$= values["act"]
OUTPUT3$= values["Protection Type"]

# OUTPUT1$: VPN-1 & FireWall-1 (String)

# OUTPUT2$: Drop (String)

# OUTPUT3$: IPS (String)

LEEF(data, delimiterOverride)🔗

data をLEEF形式のメッセージとして解析します。ヘッダーフィールドは整数で、名前付きフィールドは名前でアクセスできます。オプションでデリミタの上書きが可能です。LEEF拡張はタブ区切りであるべきですが、ヘッダーの6番目のフィールドで代替デリミタを示すこともできます。標準に準拠していないデバイスの場合はoverrideパラメータを使用してください。

DATETIME(data, fmt, handle2DigitYear)🔗

文字列を EventTimeUsec$ などのフィールド用の時刻値に変換します。time.Parse のフォーマット文字列も(オプションで)受け付けます。handle2digitYear がTRUEの場合、適切な年が選択されます(通常は現在の年ですが、年末年始の例外あり)。

🔗

data = "Sep 21 2018 17:35:54"
OUTPUT1$ = DATETIME(data, "Jan 02 2006 15:04:05")
OUTPUT2$ = data

# OUTPUT1$: 2018-09-21 17:35:54 +0000 UTC (time)

# OUTPUT2$: Sep 21 2018 17:35:54 (String)

IS_PRIVATE_IP(string)🔗

渡された(IPアドレス)文字列がプライベートIPレンジ内かどうかを判定し、ブール値を返します。現在はIPv4のみ対応し、RFC1918 で定義されたプライベートIPレンジに対してテストします。

🔗

data1 = "10.0.0.1"
data2 = "11.0.0.1"
OUTPUT1$ = IS_PRIVATE_IP(data1)
OUTPUT2$ = IS_PRIVATE_IP(data2)

# OUTPUT1$: true (bool)

# OUTPUT2$: false (bool)

IS_VALID_IP(string)🔗

渡された文字列が有効なIPアドレスかどうかを判定し、net.ParseIP を利用してブール値を返します。

🔗

data1 = "10.0.0.1"
data2 = "999.255.255.255"
data3 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"
OUTPUT1$ = IS_VALID_IP(data1)
OUTPUT2$ = IS_VALID_IP(data2)
OUTPUT3$ = IS_VALID_IP(data3)

# OUTPUT1$: true (bool)

# OUTPUT2$: false (bool)

# OUTPUT3$: true (bool)

REPLACE(data, oldString, newString)🔗

oldString を newString にすべて置換します。

🔗

data = "aaaBBBaaaCCC"
OUTPUT$ = REPLACE(data, "aaa", "zzz")

# OUTPUT$: zzzBBBzzzCCC (String)

REPLACE_REGEX(data, pattern, newString)🔗

oldPattern を newString にすべて置換します。

🔗

data = "aaaBBBaaaCCC"
OUTPUT$ = REPLACE_REGEX(data, "a+", "z")

# OUTPUT$: zBBBzCCC (String)

LENGTH(value [, "list" | "bytes" | "string" | "keys" | "object"])🔗

value の長さを返します。結果は value の型とオプションの第2引数によって異なります。LENGTH()STRLEN() の推奨代替であり、リスト・オブジェクト・文字列に対応します。

デフォルトモード(第2引数なし):

入力型 戻り値
STRING 文字列のUTF-8バイト長
LIST 要素数
OBJECT トップレベルキー数
NULL 0
その他 エラー

厳密モード(第2引数で期待型を指定、大小区別なし)。値の型が要求モードと一致しない場合、LENGTH はエラーを出さず NULL を返すため、パーサーロジックで IF ... != NULL ... のように分岐できます。

モード 対象 備考
"list" LIST, STRING, NULL リスト長。空でないトリム済み STRING1 を返す(JSONPathシングルトンのアンラップに便利)。他型は NULL
"bytes" または "string" STRING, NULL UTF-8バイト長。他型は NULL
"keys" または "object" OBJECT, NULL トップレベルキー数。他型は NULL

注意

STRING 値の場合、LENGTH()UTF-8バイト長を返します。文字(ルーン)数ではありません。アクセント付き文字や絵文字などのマルチバイト文字は1バイト以上としてカウントされます。

🔗

# String byte length (default mode)
data = "1234567890"
OUTPUT1$ = LENGTH(data)
# OUTPUT1$: 10 (int)

# Element count of a list
parts = SPLIT("a,b,c,d", ",")
OUTPUT2$ = LENGTH(parts)
# OUTPUT2$: 4 (int)

# Object key count
obj = JSON("{\"a\":1,\"b\":2,\"c\":3}")
OUTPUT3$ = LENGTH(obj)
# OUTPUT3$: 3 (int)

# Strict mode — only return a length when the value is a list
listLen = LENGTH(parts, "list")
# listLen: 4 (int)

# Strict mode — type mismatch returns NULL (no error), so the parser can branch
notAString = SPLIT(data, ",")
result = LENGTH(notAString, "bytes")
# result: NULL

STRLEN(string)🔗

非推奨

LENGTH(value) または LENGTH(value, "bytes") を使用してください。STRLEN() は後方互換性のために残されていますが、将来のリリースで削除される可能性があります。新しいパーサーではこの関数を使用しないでください。

渡された文字列のUTF-8バイト長を返します。STRING または NULL のみ受け付け、他型はエラー。NULL の場合は 0 を返します。

🔗

data = "1234567890"
OUTPUT$ = STRLEN(data)

# OUTPUT$: 10 (int)

UPPERCASE(string)🔗

渡された文字列のすべてのUnicode文字を大文字に変換して返します。strings.ToUpper() のラッパーです。

🔗

data = "aaabbbccc acme"
OUTPUT$ = UPPERCASE(data)

# OUTPUT$: AAABBBCCC ACME (String)

LOWERCASE(string)🔗

渡された文字列のすべてのUnicode文字を小文字に変換して返します。strings.ToLower() のラッパーです。

🔗

data = "AAABBBCCC ACME"
OUTPUT$ = LOWERCASE(data)

# OUTPUT$: aaabbbccc acme (String)

SANITIZE_ALL()🔗

イベントフィールド変数のnull/空値をクリーンアップします。例えば、" "、"N/A"、"n/a"、"null"、"nil"、"-" はすべてnullに設定されます。この関数はデフォルトですべてのパーサーで実行されますが、!SANITIZEALLOFF で無効化できます。

🔗

data = "N/A"
OUTPUT$ = data

# OUTPUT$: NULL (null)
!SANITIZEALLOFF
data = "N/A"
OUTPUT$ = data

# OUTPUT$: N/A (String)

TRIM(data)🔗

空白、引用符、波括弧などを削除します。

🔗

data = " aaa bbb bcc "
OUTPUT1$ = "---" + data
OUTPUT2$ = "---" + TRIM(data)

# OUTPUT1$: --- aaa bbb bcc (String)

# OUTPUT2$: ---aaa bbb bcc (String)

TRIM_ALL()🔗

すべてのイベントフィールド変数の先頭・末尾の空白を削除します。この関数はデフォルトですべてのパーサーで実行されますが、!TRIMALLOFF で無効化できます。

🔗

!TRIMALLOFF
data = " aaa bbb bcc "
OUTPUT2$ = data

# OUTPUT2$: aaa bbb bcc (String)

ADDFIELD(collection, fieldName, fieldValues)🔗

オブジェクト配列にフィールドを追加します。各オブジェクトのフィールド値は fieldValues(配列)で指定します。新しいフィールド名は fieldName で指定します。collection が NULL の場合、各値を持つ単一フィールド(fieldName)のオブジェクト配列が新規作成されます。

🔗

keys = ["httpSourceName", "httpSourceId"]
values = [json["$.httpSourceName"], json["$.httpSourceId"]]

eventMetadata$.record$ = ADDFIELD(NULL, "key$", keys)
eventMetadata$.record$ = ADDFIELD(eventMetadata$.record$, "value$", values)

# event_metadata = {

#     "httpSourceName": json["$.httpSourceName"]

#     "httpSourceId": json["$.httpSourceId"]

# }

URL_PARSE(url, silent)🔗

URLを解析します。

ヒント

パース処理の詳細は XDR でのカスタムパーサーの作成・編集・有効化 を参照してください。

silent が true の場合、URLが無効な場合でもエラーをスローせず、すべてのフィールドをnullにします。不正な形式のURLでも可能な限り抽出を試みます。期待されるURL形式は以下のいずれかです:

scheme:opaque?query#fragment
scheme://userinfo@host/path?query#fragment

🔗

http://user:password@192.1.1.1:8080/1/asdfasdfasdf.html?key=value&key2=value2#topOfTheMorning
hTtps://Example.com:443/here//is/path.html?a=1+6&x=%2f%2Fkey=%41%0Avalue&b=ddd#top
https://example.com/foo/bar/bar/../baz.html?a=1&b=2
example.com/foo/bar/bar/../baz.html?a=1&b=2
スキームが指定されていない場合(例:example.com/index.html)、scheme 値には http が設定されます。

結果のコレクションオブジェクトには、可能な限り以下の値が含まれます:

  • scheme - 正規化済み。指定されたスキームを小文字に変換、または未指定時は http
  • user - 指定されていればユーザー。
  • host_raw - 非正規化。ポートを含む指定ホスト(例:Example.com:443
  • host - 正規化済みホスト。すべて小文字、ポートなし(例:example.com
  • port - 抽出されたポート(存在する場合)
  • path_raw - 非正規化。指定されたパス(例:/foo/bar/bar/../baz.html)。URIのクエリ部分があっても末尾に ? は含まれません。
  • path - 正規化済みパス(例:/foo/bar/baz.html)。クエリ部分があっても末尾に ? は含まれません。正規化内容:
    • 文字はURIデコード(1回のみ、例:%253D%3D= にはならない)
      • /fo%6F/bar.html/foo/bar.html
    • 複数のスラッシュは1つにまとめる
      • /foo///bar.html/foo/bar.html
    • ディレクトリトラバーサルを除去
      • /foo/../bar//bar/
      • /foo/./bar//foo/bar/
  • query_raw - 非正規化。指定されたクエリ文字列(例:a=1+6&x=%2f%2Fkey=%41%0Avalue&b=ddd)。先頭の ? は含まず、順序は保持(1回のみURIデコード、失敗時はそのまま)。
  • query - 正規化済みクエリ文字列。先頭の ? は含まず、順序は保持。URIデコード実施、失敗時は該当ペアのみ非正規化でそのまま。
    • a=1&b=%44%57a=1&b=DW
  • raw_query - 非推奨。query_raw と同じで、レガシー互換のために提供。今後削除予定。
  • password - 指定されていればパスワード。
  • fragment - 指定されていればフラグメント。

🔗

data = "hTtps://Example.com:443/here//is/path.html?a=1+6&x=%2f%2Fkey=%41%0Avalue&b=ddd#top"
urlParts = URL_PARSE(data, FALSE)
OUTPUT$ = urlParts["path_raw"]

# OUTPUT$: /here//is/path.html (String)

CONTAINS(string, substring)🔗

golangの strings.Contains(string,subString) をラップし、ブール値を返します。

🔗

data     = "aaabbbccc acme"
OUTPUT1$ = CONTAINS(data, "roadrunner")
OUTPUT2$ = CONTAINS(data, "acme")

# OUTPUT1$: false    (bool)

# OUTPUT2$: true    (bool)

IDX_OF_TLD(string)🔗

indexOfTopPrivateDomain$ 用に、文字列内でトップレベルドメインがどこにあるかを示すint64を返します。-1の場合は IsTopPrivateDomainParsed$ をfalseに、それ以外はtrueに設定してください。

🔗

OUTPUT0$ = IDX_OF_TLD("aaa http://example.com")
OUTPUT1$ = IDX_OF_TLD("http://example.com")
OUTPUT2$ = IDX_OF_TLD("")

# OUTPUT0$: 0    (int)

# OUTPUT1$: 0    (int)

# OUTPUT2$: -1    (int)

PARSE_ERROR(string,string)🔗

ParseError はパーサー内で明示的にエラーを発生させます。parameters[0] は errText で coercion.EvaluateAsString() を渡します。parameter[1] はオプションで、ParserValue.BoolValue() でブール値に変換され、汎用イベントを作成するかどうかを示します。指定しない場合はデフォルトでtrueです。メッセージは他のスキーマには正規化されません。

🔗

汎用イベントを作成🔗
test = IF someVal != "Expected_value" THEN PARSE_ERROR("bad data received") ELSE "ok"
汎用イベントを作成しない🔗
tenantId$ = TENANT_LOOKUP("ngav_id", vals["Account"], PARSE_ERROR("Unable to find Taegis tenant id for Deep Armor account " + vals["Account"],"False"))

TENANT_LOOKUP(label, value, default)🔗

メッセージ内のラベルと値に基づき、Taegis Tenant ManagerでテナントIDを検索します。テナントが見つからない場合、指定したデフォルト式が評価されます。テナントが見つかった場合、第3引数は評価されません。呼び出し元はデフォルト値を指定するか、PARSE_ERROR() 関数でエラーを発生させることができます。

🔗

tenantId$ = TENANT_LOOKUP("VendorName", messageValues["customerId"], PARSE_ERROR("Customer Id not on file"))

BASE64_DECODE(string)🔗

base64エンコードされた文字列をプレーンテキストにデコードして返します。

🔗

OUTPUT$ = BASE64_DECODE("aG1lZXBcISBobWVlcFwh")

#OUTPUT$: hmeep\! hmeep\!    (String)

INT(string, base)🔗

指定した基数で数値文字列を整数に変換します。

🔗

OUTPUT$ = INT("4e0", 16)

#OUTPUT$: 1248    (int)

STRING(valueType)🔗

変数入力を文字列表現にキャストしようとします。

# In some cases "key" can be a string, empty (NULL), an array, or even map.

key = json["$.requestParameters.key"]
# By calling STRING() you guarantee objectKey is set with a value.

objectKey$ = STRING(key)
# Note: ParserValue.StringValue() isn't used directly because addition logic breaks when appending two valuetype.OBJECT to make a list (addition operator).

# valuetype.LIST, valuetype.OBJECT, and valuetype.JSONDATA returns the json string representation all others are cast to their string analogs.

OBJKEYS(value)🔗

マップまたはjsonオブジェクトのキー一覧(リスト)を返します。

🔗

 # Suppose the original json was:

 { 
    "values" : {
        "c" : "x", 
        "b" : "y", 
        "a" : "z"
    }
 }
keys = OBJKEYS(json["$.values"])
# keys is now an array of ["a", "b", "c"]

# NOTE: this function puts the values in alphabetical order

OBJVALUES(value)🔗

マップまたはjsonオブジェクトの値一覧(リスト)を返します。

🔗

 # Suppose the original json was:

 {
    "values" : {
        "c" : "x", 
        "b" : {
            "foo" : "bar"
        }, 
        "a" : "z"
    }
 }
vals = OBJVALS(json["$.values"])
# vals is now an array of ["z", "{ 'foo' : 'bar' }", "x"]

# NOTE: this function puts the values in alphabetical order by their key.  This assures that OBJKEYS and OBJVALS output their elements in the same order which is important when combining these functions with ADDFIELD().

FLATTEN(json, keyLabel, valueLabel)🔗

任意のjsonをオブジェクトのリストに変換します。

各オブジェクトは2つのフィールド(キーと値、いずれも文字列型)を持ちます。keyLabelとvalueLabelは省略可能で、デフォルトはそれぞれ "key" と "value" です。この関数は、jsonデータをGenericスキーマのtagsフィールドやThirdPartyAlertのevidence.sourceData.recordフィールドなど、KeyValuePairsIndexed型のスキーマフィールドに格納するのに便利です。

🔗

 # Suppose the original json was:

{
    "val" : { 
        "x": [
            "1",
            "2",
            "3"
        ] 
    }
}

# The output would be:

[
    {
        "key$": "val.x.0",
        "value$": "1"
    },         _
    {
        "key$": "val.x.1", 
        "value$": "2"
    },        _
    {
        "key$": "val.x.2", 
        "value$": "3"
    }
]

VALIDATE_ALL_JSONPATHS_EXIST(inputStr, jsonPaths)🔗

inputStr に埋め込まれたJSONオブジェクトが jsonPaths で指定したすべてのJSONPathを含む場合のみ TRUE を返します。いずれかのパスが欠落している場合、inputStr がJSONオブジェクトで終わっていない場合、またはJSONのパースに失敗した場合は FALSE を返します。

パラメータ:

名前 説明
inputStr STRING 末尾がJSONオブジェクトリテラル({ ... })の文字列。先頭の内容は無視されます。
jsonPaths STRING 検証する JSONPath 式のカンマ区切りリスト。

動作:

  • 関数は inputStr末尾から { ... } パターンでJSONオブジェクトを抽出します。末尾が { ... } でない場合は FALSE を返します。
  • jsonPaths 内の各パスをパースしたJSONに対して評価します。すべてのパスが少なくとも1つの要素にマッチした場合のみ TRUE を返します。
  • いずれかのエラー(無効なJSON、不正なJSONPath、型変換失敗など)はエラーを発生させず FALSE を返すため、!CONFIRMSTRING 式で安全に利用できます。

🔗

# originalData$:
# May 17 12:00:00 host alert {"event_id":"123","actor":{"id":"u1"},"action":"login"}

ok = VALIDATE_ALL_JSONPATHS_EXIST(originalData$, "$.event_id,$.actor.id,$.action")
# ok: TRUE

incomplete = VALIDATE_ALL_JSONPATHS_EXIST(originalData$, "$.event_id,$.session.id")
# incomplete: FALSE   ($.session.id is not present)

一般的なユースケース:!CONFIRMSTRING でのパーサーのゲーティング🔗

VALIDATE_ALL_JSONPATHS_EXIST は式モードのconfirm stringとして有用です。埋め込みJSONがすべての必須フィールドを含むメッセージだけにマッチさせ、下流でそれらのフィールドが必要なパーサーで部分的なイベントの誤マッチを防ぎます。

!CONFIRMWITH=EXPRESSION
!CONFIRMSTRING=VALIDATE_ALL_JSONPATHS_EXIST(originalData$, "$.event_id,$.actor.id,$.action")