טיפים ופתרון בעיות בכתיבת מנתחי נתונים
במאמר הזה מתוארות בעיות שאתם עשויים להיתקל בהן כשאתם כותבים קוד של מנתח.
כשכותבים קוד של מנתח, יכול להיות שתיתקלו בשגיאות אם הוראות הניתוח לא פועלות כמצופה. מצבים שעלולים לגרום לשגיאות כוללים את המצבים הבאים:
- תבנית
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 מוגדרות מראש ובהצהרות של ביטויים רגילים. תבניות 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 יפורש כמחרוזת המילולית ולא כתווית טאב.
הדוגמה הבאה היא יומן גולמי מקורי ויומן בפורמט 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.