פתרון בעיות בקוד של כלי הניתוח
במאמר הזה מתוארות בעיות שאתם עשויים להיתקל בהן כשאתם כותבים קוד של מנתח.
כשכותבים קוד של מנתח, יכול להיות שתיתקלו בשגיאות אם הוראות הניתוח לא פועלות כמצופה. מצבים שעלולים לגרום לשגיאות כוללים את המצבים הבאים:
- תבנית
Grokנכשלת - פעולה של
renameאוreplaceנכשלת - שגיאות תחביר בקוד של כלי הניתוח
שיטות נפוצות בקוד של כלי הניתוח
בקטעים הבאים מתוארות שיטות מומלצות, טיפים ופתרונות שיעזרו לכם לפתור בעיות.
הימנעות משימוש בנקודות או במקפים בשמות של משתנים
השימוש במקפים ובנקודות בשמות של משתנים עלול לגרום להתנהגות לא צפויה, לרוב כשמבצעים פעולות merge כדי לאחסן ערכים בשדות UDM. יכול להיות שתיתקלו גם בבעיות בניתוח נתונים לסירוגין.
לדוגמה, אל תשתמשו בשמות המשתנים הבאים:
my.variable.resultmy-variable-result
במקום זאת, צריך להשתמש בשם המשתנה הבא: my_variable_result.
אל תשתמשו במונחים עם משמעות מיוחדת כשם של משתנה
למילים מסוימות, כמו event ו-timestamp, יכולה להיות משמעות מיוחדת בקוד של כלי הניתוח.
המחרוזת event משמשת לעיתים קרובות לייצוג רשומה יחידה של UDM, והיא משמשת בהצהרה @output. אם הודעת יומן כוללת שדה בשם event, או אם מגדירים משתנה ביניים בשם event, וקוד המנתח משתמש במילה event בהצהרה @output, תוצג הודעת שגיאה לגבי התנגשות בשם.
משנים את השם של המשתנה הזמני למשהו אחר, או משתמשים במונח event1 כקידומת בשמות של שדות UDM ובמשפט @output.
המילה timestamp מייצגת את חותמת הזמן של היצירה של היומן הגולמי המקורי. ערך שמוגדר במשתנה הביניים הזה נשמר בשדה metadata.event_timestamp UDM. המונח @timestamp מייצג את התאריך והשעה שבהם יומן הגולמי פוענח כדי ליצור רשומה ב-UDM.
בדוגמה הבאה, השדה metadata.event_timestamp UDM מוגדר לתאריך ולשעה שבהם יומן הגולמי פוענח.
# Save the log parse date and time to the timestamp variable
mutate {
rename => {
"@timestamp" => "timestamp"
}
}
בדוגמה הבאה, השדה metadata.event_timestamp UDM מוגדר לתאריך ולשעה שחולצו מהיומן הגולמי המקורי ונשמרו במשתנה הביניים when.
# Save the event timestamp to timestamp variable
mutate {
rename => {
"when" => "timestamp"
}
}
אל תשתמשו במונחים הבאים כמשתנים:
- collectiontimestamp
- createtimestamp
- אירוע
- filename
- הודעה
- מרחב שמות
- פלט
- onerrorcount
- חותמת זמן
- אזור זמן
שמירת כל ערך נתונים בשדה נפרד ב-UDM
אל תאחסנו כמה שדות בשדה UDM יחיד על ידי שרשור שלהם עם תו מפריד. לדוגמה:
"principal.user.first_name" => "first:%{first_name},last:%{last_name}"
במקום זאת, מאחסנים כל ערך בשדה נפרד של UDM.
"principal.user.first_name" => "%{first_name}"
"principal.user.last_name" => "%{last_name}"
שימוש ברווחים במקום בטאבים בקוד
אל תשתמשו בכרטיסיות בקוד של כלי הניתוח. משתמשים רק ברווחים, ומוסיפים 2 רווחים בכל פעם להזחה.
לא לבצע כמה פעולות מיזוג בפעולה אחת
אם ממזגים כמה שדות בפעולה אחת, יכול להיות שיופיעו תוצאות לא עקביות. במקום זאת, כדאי להציב הצהרות merge בפעולות נפרדות.
לדוגמה, מחליפים את הדוגמה הבאה:
mutate {
merge => {
"security_result.category_details" => "category_details"
"security_result.category_details" => "super_category_details"
}
}
עם זה:
mutate {
merge => {
"security_result.category_details" => "category_details"
}
}
mutate {
merge => {
"security_result.category_details" => "super_category_details"
}
}
בחירה בין ביטויי תנאי if לבין if else
אם הערך המותנה שאתם בודקים יכול להתאים רק למקרה אחד, אתם צריכים להשתמש במשפט התנאי if else. הגישה הזו קצת יותר יעילה. עם זאת, אם יש תרחיש שבו הערך שנבדק יכול להתאים יותר מפעם אחת, צריך להשתמש בכמה הצהרות if שונות ולסדר את ההצהרות מהמקרה הגנרי ביותר למקרה הספציפי ביותר.
בחירת קבוצה מייצגת של קובצי יומן לבדיקת שינויים במנתח
מומלץ לבדוק את קוד הניתוח באמצעות דוגמאות של יומנים גולמיים במגוון רחב של פורמטים. כך תוכלו למצוא יומנים ייחודיים או מקרים חריגים שהכלי לניתוח עשוי להזדקק לטיפול בהם.
הוספת הערות תיאוריות לקוד של כלי הניתוח
מוסיפים הערות לקוד של כלי הניתוח שמסבירות למה ההצהרה חשובה, ולא מה ההצהרה עושה. ההערה עוזרת לכל מי שמנהל את מנתח התוכן לעקוב אחרי התהליך. לדוגמה:
# only assign a Namespace if the source address is RFC 1918 or Loopback IP address
if [jsonPayload][id][orig_h] =~ /^(127(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{3\}$)|(10(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{3\}$)|(192\.168(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{2\}$)|(172\.(?:1[6-9]|2\d|3[0-1])(?:\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))\{2\}$)/ {
mutate {
replace => {
"event1.idm.read_only_udm.principal.namespace" => "%{resource.labels.project_id}"
}
}
}
הגדרה מוקדמת של משתני ביניים
לפני שמחלצים ערכים מהיומן הגולמי המקורי, מאתחלים משתני ביניים שישמשו לאחסון ערכי בדיקה.
כך נמנעת שגיאה שמוחזרת ומציינת שהמשתנה המתווך לא קיים.
ההצהרה הבאה מקצה את הערך במשתנה product לשדה metadata.product_name UDM.
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
}
אם המשתנה product לא קיים, תוצג השגיאה הבאה:
"generic::invalid_argument: pipeline failed: filter mutate (4) failed: replace failure: field \"event1.idm.read_only_udm.metadata.product_name\": source field \"product\": field not set"
אפשר להוסיף הצהרה של on_error כדי לזהות את השגיאה. לדוגמה:
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
on_error => "_error_does_not_exist"
}
בדוגמה שלמעלה, השגיאה בניתוח נתפסת בהצלחה על ידי משתנה בוליאני ביניים שנקרא _error_does_not_exist. היא לא מאפשרת להשתמש במשתנה product במשפט מותנה, למשל if.
לדוגמה:
if [product] != "" {
mutate{
replace => {
"event1.idm.read_only_udm.metadata.product_name" => "%{product}"
}
}
on_error => "_error_does_not_exist"
}
הדוגמה הקודמת מחזירה את השגיאה הבאה כי פסוקית התנאי if לא תומכת בהצהרות on_error:
"generic::invalid_argument: pipeline failed: filter conditional (4) failed: failed to evaluate expression: generic::invalid_argument: "product" not found in state data"
כדי לפתור את הבעיה הזו, צריך להוסיף בלוק נפרד של הצהרות שמאכלס את משתני הביניים לפני הפעלת ההצהרות של מסנן החילוץ (json, csv, xml, kv או grok).
הנה דוגמה.
filter {
# Initialize intermediate variables for any field you will use for a conditional check
mutate {
replace => {
"timestamp" => ""
"does_not_exist" => ""
}
}
# load the logs fields from the message field
json {
source => "message"
array_function => "split_columns"
on_error => "_not_json"
}
}
קטע הקוד המעודכן של מנתח התוכן מטפל בתרחישים השונים באמצעות משפט מותנה כדי לבדוק אם השדה קיים. בנוסף, ההצהרה on_error מטפלת בשגיאות שעלולות להתרחש.
המרת SHA-256 ל-base64
בדוגמה הבאה, הערך SHA-256 מחולץ, מקודד ב-base64, הנתונים המקודדים מומרים למחרוזת הקסדצימלית, ואז שדות ספציפיים מוחלפים בערכים שחולצו ועברו עיבוד.
if [Sha256] != ""
{
base64
{
encoding => "RawStandard"
source => "Sha256"
target => "base64_sha256"
on_error => "base64_message_error"
}
mutate
{
convert =>
{
"base64_sha256" => "bytestohex"
}
on_error => "already_a_string"
}
mutate
{
replace =>
{
"event.idm.read_only_udm.network.tls.client.certificate.sha256" => "%{base64_sha256}"
"event.idm.read_only_udm.target.resource.name" => "%{Sha256}"
}
}
}
טיפול בשגיאות בהצהרות של כלי הניתוח
לא נדיר שיומן אירועים נכנס יהיה בפורמט לא צפוי או שיכיל נתונים בפורמט שגוי.
אפשר ליצור את מנתח התוכן כך שיטפל בשגיאות האלה. מומלץ להוסיף
on_error handlers למסנן החילוץ, ואז לבדוק את משתנה הביניים לפני שממשיכים לקטע הבא של לוגיקת הניתוח.
בדוגמה הבאה נעשה שימוש במסנן החילוץ json עם הצהרת on_error כדי להגדיר את המשתנה הבוליאני _not_json. אם הערך של _not_json הוא true, המשמעות היא שרשומת היומן הנכנסת לא הייתה בפורמט JSON תקין, והניתוח שלה נכשל. אם המשתנה _not_json הוא false,
הערך של רשומת היומן הנכנסת היה בפורמט JSON תקין.
# load the incoming log from the default message field
json {
source => "message"
array_function => "split_columns"
on_error => "_not_json"
}
אפשר גם לבדוק אם שדה מסוים הוא בפורמט הנכון. בדוגמה הבאה, המערכת בודקת אם הערך של _not_json הוא true, כלומר היומן לא היה בפורמט הצפוי.
# Test that the received log matches the expected format
if [_not_json] {
drop { tag => "TAG_MALFORMED_MESSAGE" }
} else {
# timestamp is always expected
if [timestamp] != "" {
# ...additional parser logic goes here …
} else {
# if the timestamp field does not exist, it's not a log source
drop { tag => "TAG_UNSUPPORTED" }
}
}
כך אפשר לוודא שהניתוח לא ייכשל אם היומנים מוזנים בפורמט שגוי לסוג היומן שצוין.
משתמשים במסנן drop עם המשתנה tag כדי שהתנאי יתועד בטבלת מדדי ההטמעה ב-BigQuery.
TAG_UNSUPPORTEDTAG_MALFORMED_ENCODINGTAG_MALFORMED_MESSAGETAG_NO_SECURITY_VALUE
המסנן drop מונע מהכלי לניתוח נתונים לעבד את יומן הרישום הגולמי, לנרמל את השדות וליצור רשומת UDM. היומן הגולמי המקורי עדיין מוזן ל-Google Security Operations ואפשר לחפש בו באמצעות חיפוש יומנים גולמיים ב-Google SecOps.
הערך שמועבר למשתנה tag מאוחסן בשדה drop_reason_code בטבלת מדדי ההטמעה. אפשר להריץ שאילתה אד-הוק על הטבלה, בדומה לשאילתה הבאה:
SELECT
log_type,
drop_reason_code,
COUNT(drop_reason_code) AS count
FROM `datalake.ingestion_metrics`
GROUP BY 1,2
ORDER BY 1 ASC
פתרון בעיות שקשורות לשגיאות אימות
כשיוצרים מנתח, יכול להיות שתיתקלו בשגיאות שקשורות לאימות. לדוגמה, שדה חובה לא מוגדר ברשומת UDM. השגיאה עשויה להיראות כך:
Error: generic::unknown: invalid event 0: LOG_PARSING_GENERATED_INVALID_EVENT: "generic::invalid_argument: udm validation failed: target field is not set"
קוד הניתוח מופעל בהצלחה, אבל רשומת ה-UDM שנוצרה לא כוללת את כל שדות ה-UDM הנדרשים, כפי שהוגדרו על ידי הערך שהוצב ב-metadata.event_type. אלה דוגמאות נוספות שיכולות לגרום לשגיאה הזו:
- אם הערך של
metadata.event_typeהואUSER_LOGINוהשדהtarget.user valueUDM לא מוגדר. - אם הערך של
metadata.event_typeהואNETWORK_CONNECTIONוהשדהtarget.hostnameUDM לא מוגדר.
מידע נוסף על השדה metadata.event_type UDM ועל השדות הנדרשים זמין במדריך לשימוש ב-UDM.
אחת מהאפשרויות לפתרון בעיות שגיאה מהסוג הזה היא להתחיל בהגדרת ערכים סטטיים בשדות UDM. אחרי שמגדירים את כל השדות הנדרשים ב-UDM, בודקים את יומן הרישום המקורי כדי לראות אילו ערכים צריך לנתח ולשמור ברשומת ה-UDM. אם יומן הגולמי המקורי לא מכיל שדות מסוימים, יכול להיות שתצטרכו להגדיר ערכי ברירת מחדל.
התבנית הבאה היא דוגמה ספציפית לסוג אירוע USER_LOGIN, שממחישה את הגישה הזו.
כדאי לשים לב לנקודות הבאות:
- התבנית מאתחלת משתני ביניים ומגדירה כל אחד מהם למחרוזת סטטית.
- הקוד בקטע Field Assignment [הקצאת שדות] מגדיר את הערכים במשתנים ביניים לשדות UDM.
אפשר להרחיב את הקוד הזה על ידי הוספה של משתני ביניים נוספים ושדות UDM. אחרי שמזהים את כל השדות ב-UDM שצריך למלא, מבצעים את הפעולות הבאות:
בקטע Input Configuration (הגדרת קלט), מוסיפים קוד שמחלץ שדות מיומן הגולמי המקורי ומגדיר את הערכים למשתני הביניים.
בקטע Date Extract (חילוץ תאריך), מוסיפים קוד שמחלץ את חותמת הזמן של האירוע מיומן הגולמי המקורי, משנה אותה ומגדיר אותה למשתנה הביניים.
במידת הצורך, מחליפים את הערך המאותחל שמוגדר בכל משתנה ביניים במחרוזת ריקה.
filter {
mutate {
replace => {
# UDM > Metadata
"metadata_event_timestamp" => ""
"metadata_vendor_name" => "Example"
"metadata_product_name" => "Example SSO"
"metadata_product_version" => "1.0"
"metadata_product_event_type" => "login"
"metadata_product_log_id" => "12345678"
"metadata_description" => "A user logged in."
"metadata_event_type" => "USER_LOGIN"
# UDM > Principal
"principal_ip" => "192.168.2.10"
# UDM > Target
"target_application" => "Example Connect"
"target_user_user_display_name" => "Mary Smith"
"target_user_userid" => "mary@example.com"
# UDM > Extensions
"auth_type" => "SSO"
"auth_mechanism" => "USERNAME_PASSWORD"
# UDM > Security Results
"securityResult_action" => "ALLOW"
"security_result.severity" => "LOW"
}
}
# ------------ Input Configuration --------------
# Extract values from the message using one of the extraction filters: json, kv, grok
# ------------ Date Extract --------------
# If the date {} function is not used, the default is the normalization process time
# ------------ Field Assignment --------------
# UDM Metadata
mutate {
replace => {
"event1.idm.read_only_udm.metadata.vendor_name" => "%{metadata_vendor_name}"
"event1.idm.read_only_udm.metadata.product_name" => "%{metadata_product_name}"
"event1.idm.read_only_udm.metadata.product_version" => "%{metadata_product_version}"
"event1.idm.read_only_udm.metadata.product_event_type" => "%{metadata_product_event_type}"
"event1.idm.read_only_udm.metadata.product_log_id" => "%{metadata_product_log_id}"
"event1.idm.read_only_udm.metadata.description" => "%{metadata_description}"
"event1.idm.read_only_udm.metadata.event_type" => "%{metadata_event_type}"
}
}
# Set the UDM > auth fields
mutate {
replace => {
"event1.idm.read_only_udm.extensions.auth.type" => "%{auth_type}"
}
merge => {
"event1.idm.read_only_udm.extensions.auth.mechanism" => "auth_mechanism"
}
}
# Set the UDM > principal fields
mutate {
merge => {
"event1.idm.read_only_udm.principal.ip" => "principal_ip"
}
}
# Set the UDM > target fields
mutate {
replace => {
"event1.idm.read_only_udm.target.user.userid" => "%{target_user_userid}"
"event1.idm.read_only_udm.target.user.user_display_name" => "%{target_user_user_display_name}"
"event1.idm.read_only_udm.target.application" => "%{target_application}"
}
}
# Set the UDM > security_results fields
mutate {
merge => {
"security_result.action" => "securityResult_action"
}
}
# Set the security result
mutate {
merge => {
"event1.idm.read_only_udm.security_result" => "security_result"
}
}
# ------------ Output the event --------------
mutate {
merge => {
"@output" => "event1"
}
}
}
ניתוח טקסט לא מובנה באמצעות פונקציית Grok
כשמשתמשים בפונקציית Grok כדי לחלץ ערכים מטקסט לא מובנה, אפשר להשתמש בדפוסי Grok מוגדרים מראש ובהצהרות של ביטויים רגולריים. הבנת דפוסים
מקלה על קריאת הקוד. אם הביטוי הרגולרי לא כולל תווים מקוצרים (כמו \w, \s), אפשר להעתיק ולהדביק את ההצהרה ישירות לקוד של כלי הניתוח.
תבניות Grok הן שכבת הפשטה נוספת בהצהרה, ולכן הן עלולות להקשות על פתרון בעיות כשנתקלים בשגיאה. הדוגמה הבאה היא פונקציית Grok שמכילה גם דפוסי Grok מוגדרים מראש וגם ביטויים רגולריים.
grok {
match => {
"message" => [
"%{NUMBER:when}\\s+\\d+\\s%{SYSLOGHOST:srcip} %{WORD:action}\\/%{NUMBER:returnCode} %{NUMBER:size} %{WORD:method} (?P<url>\\S+) (?P<username>.*?) %{WORD}\\/(?P<tgtip>\\S+).*"
]
}
}
יכול להיות שמשפט חילוץ ללא תבניות Grok יניב ביצועים טובים יותר. לדוגמה, בדוגמה הבאה נדרשים פחות ממחצית שלבי העיבוד כדי להגיע להתאמה. זה שיקול חשוב כשמדובר במקור יומן שעשוי להיות בעל נפח גבוה.
הסבר על ההבדלים בין ביטויים רגולריים של RE2 לבין ביטויים רגולריים של PCRE
מנתחי הנתונים של Google SecOps משתמשים ב-RE2 כמנוע לביטויים רגולריים. אם אתם מכירים את התחביר של PCRE, יכול להיות שתבחינו בהבדלים. דוגמה אחת:
זוהי הצהרת PCRE: (?<_custom_field>\w+)\s
ההצהרה הבאה היא הצהרת RE2 לקוד מנתח: (?P<_custom_field>\\w+)\\s
חשוב להשתמש בתו בריחה (escape) עם תווי הבריחה
Google SecOps מאחסן נתוני יומן גולמיים נכנסים בפורמט מקודד JSON. הסיבה לכך היא לוודא שמחרוזות תווים שנראות כמו קיצור דרך של ביטוי רגולרי יפורשו כמחרוזת המילולית. לדוגמה, \t יפורש כמחרוזת מילולית ולא כתו Tab.
הדוגמה הבאה היא יומן גולמי מקורי ויומן בפורמט JSON מקודד.
שימו לב לתו הבריחה שנוסף לפני כל תו לוכסן הפוך שמקיף את המונח entry.
זוהי יומן הרישום המקורי:
field=\entry\
היומן הבא הומר לפורמט JSON מקודד:
field=\\entry\\
כשמשתמשים בביטוי רגולרי בקוד של כלי הניתוח, צריך להוסיף תווי escape נוספים אם רוצים לחלץ רק את הערך. כדי להתאים קו נטוי הפוך ביומן הגולמי המקורי, צריך להשתמש בארבעה קווים נטויים הפוכים בהצהרת החילוץ.
הביטוי הרגולרי הבא מתאים לקוד של מנתח:
^field=\\\\(?P<_value>.*)\\\\$
זו התוצאה שנוצרה. _value קבוצה עם שם מאחסנת את המונח entry:
"_value": "entry"
כשמעבירים הצהרה של ביטוי רגולרי רגיל לקוד של מנתח, צריך להוסיף תו בריחה לקיצורי דרך של ביטויים רגולריים בהצהרת החילוץ.
לדוגמה, שינוי של \s ל-\\s.
לא משנים תווים מיוחדים של ביטויים רגולריים כשמבצעים בריחה כפולה בהצהרת החילוץ. לדוגמה, \\ לא ישתנה וייראה כך: \\.
דוגמה לביטוי רגולרי רגיל:
^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$
הביטוי הרגולרי הבא משתנה כדי לפעול בקוד של כלי הניתוח.
^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$
בטבלה הבאה מפורט מתי ביטוי רגולרי רגיל צריך לכלול תווים נוספים לביטול בריחה לפני שכוללים אותו בקוד של כלי הניתוח.
| ביטוי רגולרי | ביטוי רגולרי ששונה עבור קוד מנתח | תיאור השינוי |
|---|---|---|
\s |
\\s |
צריך להשתמש בתו בריחה (escape) עם תווים מקוצרים. |
\. |
\\. |
צריך להשתמש בתו בריחה (escape) לסימון תווים שמורים. |
\\" |
\\\" |
צריך להשתמש בתו בריחה (escape) לסימון תווים שמורים. |
\] |
\\] |
צריך להשתמש בתו בריחה (escape) לסימון תווים שמורים. |
\| |
\\| |
צריך להשתמש בתו בריחה (escape) לסימון תווים שמורים. |
[^\\]+ |
[^\\\\]+ |
צריך להוסיף תווי בריחה (escape) לתווים מיוחדים בתוך קבוצת מחלקות תווים. |
\\\\ |
\\\\ |
תווים מיוחדים מחוץ לקבוצת מחלקות תווים או תווים מקוצרים לא דורשים בריחה נוספת. |
ביטויים רגולריים חייבים לכלול קבוצה לחילוץ עם שם
ביטוי רגולרי, כמו "^.*$", הוא תחביר RE2 תקין. עם זאת, בניתוח של קוד parser
הוא נכשל עם השגיאה הבאה:
"ParseLogEntry failed: pipeline failed: filter grok (0) failed: failed to parse data with all match
patterns"
עליך להוסיף ביטוי תקין לקבוצה לחילוץ. אם משתמשים בתבניות Grok, הן כוללות קבוצה לחילוץ עם שם כברירת מחדל. כשמשתמשים בהחלפות של ביטויים רגולריים, חשוב לכלול קבוצה עם שם.
הנה דוגמה לביטוי רגולרי בקוד של כלי הניתוח:
"^(?P<_catchall>.*$)"
זו התוצאה, שבה מוצג הטקסט שהוקצה לקבוצה בשם _catchall.
"_catchall": "User \"BOB\" logged on to workstation \"DESKTOP-01\"."
משתמשים בקבוצה בשם catchall כדי להתחיל לבנות את הביטוי
כשיוצרים הצהרת חילוץ, מתחילים עם ביטוי שכולל יותר ממה שרוצים. אחר כך מרחיבים את הביטוי שדה אחד בכל פעם.
בדוגמה הבאה מתחילים להשתמש בקבוצה עם שם (_catchall) שתואמת להודעה כולה. לאחר מכן, המערכת בונה את הביטוי בשלבים על ידי התאמה של חלקים נוספים מהטקסט. בכל שלב, הקבוצה שנקראת _catchall מכילה פחות מהטקסט המקורי. ממשיכים וחוזרים על הפעולה שלב אחרי שלב כדי להתאים את ההודעה עד שלא צריך יותר את הקבוצה שנקראת _catchall.
| שלב | ביטוי רגולרי בקוד של כלי הניתוח | הפלט של קבוצת הלכידה _catchall |
|---|---|---|
| 1 | "^(?P<_catchall>.*$)" |
User \"BOB\" logged on to workstation \"DESKTOP-01\". |
| 2 | ^User\s\\\"(?P<_catchall>.*$) |
BOB\" logged on to workstation \"DESKTOP-01\". |
| 3 | ^User\s\\\"(?P<_user>.*?)\\\"\s(?P<_catchall>.*$) |
logged on to workstation \"DESKTOP-01\". |
| ממשיכים עד שהביטוי תואם למחרוזת הטקסט כולה. | ||
תו בריחה (escape) לתווים מקוצרים בביטוי הרגולרי
חשוב לזכור להשתמש בתו בריחה לקיצורי דרך של ביטויים רגולריים כשמשתמשים בביטוי בקוד של כלי הניתוח. זוהי דוגמה למחרוזת טקסט ולביטוי הרגולרי הרגיל שמחלץ את המילה הראשונה, This.
This is a sample log.
הביטוי הרגולרי הרגיל הבא מחלץ את המילה הראשונה, This.
עם זאת, כשמריצים את הביטוי הזה בקוד של כלי הניתוח, התוצאה לא כוללת את האות s.
| ביטוי רגולרי רגיל | הפלט של קבוצת הלכידה _firstWord |
|---|---|
"^(?P<_firstWord>[^\s]+)\s.*$" |
"_firstWord": "Thi", |
הסיבה לכך היא שביטויים רגולריים בקוד של כלי הניתוח דורשים הוספה של תו בריחה נוסף לתווים מקוצרים. בדוגמה הקודמת, צריך לשנות את \s ל-\\s.
| ביטוי רגולרי מתוקן לקוד של כלי הניתוח | הפלט של קבוצת הלכידה _firstWord |
|---|---|
"^(?P<_firstWord>[^\\s]+)\\s.*$" |
"_firstWord": "This", |
הכלל הזה חל רק על קיצורי דרך לתווים, כמו \s, \r ו-\t.
אין צורך להשתמש בתו בריחה עם תווים אחרים, כמו '`'.
תבנית Grok לחילוץ כתובות אימייל שמתחילות בספרה
במנתחי נתונים ספציפיים ללקוח ובתוספים של מנתחי קטעי קוד, אל תשתמשו בתבנית EMAILADDRESS Grok כדי לחלץ כתובות אימייל שמתחילות בספרה. כפתרון עקיף, אפשר להשתמש בתבנית DATA Grok ואז להחיל אימות של ביטוי רגולרי בשלב המיפוי.
דוגמה מלאה
בקטע הזה מתוארים הכללים הקודמים כדוגמה מקצה לקצה. זוהי מחרוזת טקסט לא מובנית, והביטוי הרגולרי הרגיל שנכתב כדי לנתח את המחרוזת. לבסוף, הוא כולל את הביטוי הרגולרי ששונה ופועל בקוד של מנתח התוכן.
זו מחרוזת הטקסט המקורית.
User "BOB" logged on to workstation "DESKTOP-01".
הדוגמה הבאה היא ביטוי רגולרי רגיל של RE2 שמנתח את מחרוזת הטקסט.
^.*?\\\"(?P<_user>[^\\]+)\\\"\s(?:(logged\son|logged\soff))\s.*?\\\"(?P<_device>[^\\]+)\\\"\.$
הביטוי הזה מחלץ את השדות הבאים.
| קבוצת התאמה | מיקום הדמות | מחרוזת טקסט |
|---|---|---|
| התאמה מלאה | 0-53 | User \"BOB\" logged on to workstation \"DESKTOP-01\". |
| קבוצה `_user` | 7-10 | BOB |
| קבוצה 2. | 13-22 | logged on |
| הקבוצה '_device' | 40-50 | DESKTOP-01 |
זה הביטוי ששונה. הביטוי הרגולרי הרגיל של RE2 שונה כדי לפעול בקוד של מנתח התוכן.
^.*?\\\"(?P<_user>[^\\\\]+)\\\"\\s(?:(logged\\son|logged\\soff))\\s.*?\\\"(?P<_device>[^\\\\]+)\\\"\\.$
הבעיה עדיין לא נפתרה? קבלת תשובות מחברי הקהילה וממומחי Google SecOps.