רישום מובנה ביומן

במאמר הזה נסביר על הקונספט של רישום ביומן במבנה מוגדר ועל השיטות להוספת מבנה לשדות של מטען ייעודי (payload) של רשומות ביומן. כשמטען ייעודי של יומן מעוצב כאובייקט JSON והאובייקט הזה מאוחסן בשדה jsonPayload, רשומת היומן נקראת יומן מובנה. ביומנים האלה אפשר ליצור שאילתות שמחפשות נתיבי JSON ספציפיים, ולבצע אינדוקס של שדות ספציפיים במטען הייעודי (payload) של היומן. לעומת זאת, אם מטען הייעודי (payload) של היומן מעוצב כמחרוזת ומאוחסן בשדה textPayload, רשומת היומן היא לא מובנית. אפשר לחפש בשדה הטקסט, אבל אי אפשר ליצור אינדקס של התוכן שלו.

כדי ליצור רשומות יומן מובנות, אפשר לבצע אחת מהפעולות הבאות:

  • קוראים לשיטת ה-API‏ entries.write ומספקים LogEntry בפורמט מלא.
  • משתמשים בפקודה gcloud logging write.
  • שימוש בספריית לקוח של Cloud Logging שכותבת יומנים מובנים.
  • משתמשים בשירות BindPlane.
  • שימוש בסוכן לכתיבת יומנים:

    • חלק מה Google Cloud שירותים מכילים סוכן רישום ביומן משולב ששולח את הנתונים שנכתבו ב-stdout או ב-stderr כיומנים ל-Cloud Logging. אפשר להשתמש בגישה הזו בשירותים כמו Google Kubernetes Engine,‏ הסביבה הגמישה של App Engine ופונקציות Cloud Run. Google Cloud

    • במכונות וירטואליות (VM) של Compute Engine, אפשר להתקין ולהגדיר את סוכן תפעול או את סוכן ה-Logging מדור קודם, ואז להשתמש בסוכן שהותקן כדי לשלוח יומנים ל-Cloud Logging.

בסעיפים הבאים יש מידע נוסף על הגישות האלה.

כתיבת יומנים באמצעות ספריות לקוח או ה-API

אפשר לכתוב נתוני יומנים באמצעות ספריות הלקוח של Cloud Logging, שקוראות ל-Cloud Logging API, או באמצעות קריאה ישירה ל-Cloud Logging API. ספריות לקוח יכולות לפשט את האכלוס של שדות ה-JSON המיוחדים על ידי תיעוד אוטומטי של חלק מהמידע ועל ידי מתן ממשקים לאכלוס השדות בצורה מתאימה. עם זאת, כדי לקבל שליטה מלאה במבנה של נתוני ה-payload, צריך להפעיל ישירות את Cloud Logging API ולהעביר את המבנה המלא של LogEntry אל Cloud Logging API.

מידע נוסף זמין במאמר בנושא entries.write.

דוגמאות קוד מופיעות במאמר בנושא כתיבת יומנים מובְנים.

כתיבת יומנים באמצעות ה-CLI של gcloud

אפשר לכתוב נתוני יומן באמצעות ה-CLI של gcloud. הממשק תומך ביומנים לא מובנים וביומנים מובנים. כשרוצים לכתוב יומן מובנה, צריך לספק לפקודה אובייקט JSON שעבר סריאליזציה.

מדריך למתחילים: כתיבה של רשומות ביומן וביצוע שאילתות לגביהן באמצעות Google Cloud CLI

דוגמאות קוד מופיעות במאמר בנושא gcloud logging write.

כתיבת יומנים באמצעות BindPlane

אפשר להשתמש בשירות BindPlane כדי לשלוח יומנים אל Logging. במקרה של יומנים כאלה, המטען הייעודי (payload) הוא בפורמט JSON ומובנה בהתאם למערכת המקור. למידע על איתור וצפייה ביומנים שנקלטים באמצעות BindPlane, אפשר לעיין במדריך למתחילים של BindPlane.

כתיבת יומנים באמצעות סוכן

כדי לקבל יומנים מהמכונות של Compute Engine, אפשר להשתמש בסוכן התפעול או בסוכן Cloud Logging מדור קודם. שני הסוכנים יכולים לאסוף מדדים מאפליקציות של צד שלישי, ושניהם תומכים ברישום ביומן במבנה:

  • Ops Agent הוא הסוכן המומלץ לאיסוף טלמטריה ממכונות Compute Engine. הסוכן הזה משלב רישום ביומן ומדדים בסוכן יחיד, מספק הגדרה מבוססת-YAML וכולל רישום ביומן עם תפוקה גבוהה.

    במאמר הגדרת סוכן תפעול מוסבר איך מגדירים את סוכן תפעול כך שיתמוך ברישום ביומן במבנה או בהתאמה אישית של מבנה היומן.

  • סוכן Logging מדור קודם של Cloud אוסף יומנים. הסוכן הזה לא אוסף סוגים אחרים של טלמטריה.

החלק שנותר בקטע הזה מתייחס ספציפית לסוכן Logging מדור קודם.

סוכן Logging: שדות JSON מיוחדים

חלק מהשדות באובייקט JSON מזוהים כשדות מיוחדים על ידי סוכן Logging מדור קודם, והם מחולצים למבנה LogEntry. אפשר להשתמש בשדות ה-JSON המיוחדים האלה כדי להגדיר את השדות הבאים ב-LogEntry:

  • severity
  • spanId
  • labels בהגדרת משתמש
  • httpRequest

מכיוון ש-JSON מדויק ורב-תכליתי יותר משורות טקסט, אפשר להשתמש באובייקטים של JSON כדי לכתוב הודעות מרובות שורות ולהוסיף מטא-נתונים.

כדי ליצור רשומות יומן מובנות לאפליקציות שלכם באמצעות הפורמט הפשוט, אפשר לעיין בטבלה הבאה שבה מפורטים השדות והערכים שלהם ב-JSON:

שדה ביומן JSON LogEntry שדה פונקציית הסוכן של Cloud Logging ערך לדוגמה
severity severity הסוכן של Logging מנסה להתאים מגוון של מחרוזות נפוצות של חומרת הבעיה, כולל הרשימה של מחרוזות LogSeverity שמזוהות על ידי Logging API. "severity":"ERROR"
message textPayload (או חלק מ- jsonPayload) ההודעה שמופיעה בשורת רשומה ביומן בכלי Logs Explorer. "message":"There was an error in the application."

הערה: הערך message נשמר כ-textPayload אם זה השדה היחיד שנשאר אחרי שהסוכן Logging מעביר את שאר השדות המיוחדים ו detect_json לא הופעל. אחרת, הערך message נשאר ב-jsonPayload. ‫detect_json לא רלוונטי לסביבות ניהול רישום ביומן כמו Google Kubernetes Engine. אם רשומת היומן מכילה מעקב אחר מחסנית חריגים, צריך להגדיר את המעקב אחר מחסנית החריגים בשדה היומן message בפורמט JSON, כדי שאפשר יהיה לנתח את המעקב אחר מחסנית החריגים ולשמור אותו ב-Error Reporting.
log (legacy Google Kubernetes Engine only) textPayload ההגדרה הזו רלוונטית רק לגרסה הקודמת של Google Kubernetes Engine: אם אחרי העברת שדות מיוחדים נשאר רק שדה log, השדה הזה יישמר בתור textPayload.
httpRequest httpRequest רשומה מובנית בפורמט של השדה LogEntry HttpRequest. "httpRequest":{"requestMethod":"GET"}
שדות שקשורים לזמן timestamp מידע נוסף זמין במאמר בנושא שדות שקשורים לזמן. "time":"2020-10-12T07:20:50.52Z"
logging.googleapis.com/insertId insertId מידע נוסף זמין במאמר insertId בדף LogEntry. "logging.googleapis.com/insertId":"42"
logging.googleapis.com/labels labels הערך בשדה הזה חייב להיות רשומה מובנית. מידע נוסף זמין במאמר labels בדף LogEntry. "logging.googleapis.com/labels": {"user_label_1":"value_1","user_label_2":"value_2"}
logging.googleapis.com/operation operation הערך של השדה הזה משמש גם את הכלי Logs Explorer לקיבוץ רשומות יומן שקשורות זו לזו. מידע נוסף זמין במאמר בנושא operation בדף LogEntry. "logging.googleapis.com/operation": {"id":"get_data","producer":"github.com/MyProject/MyApplication", "first":"true"}
logging.googleapis.com/sourceLocation sourceLocation מידע על מיקום קוד המקור שמשויך לרשומה ביומן, אם יש. מידע נוסף זמין במאמר LogEntrySourceLocation בדף LogEntry. "logging.googleapis.com/sourceLocation": {"file":"get_data.py","line":"142","function":"getData"}
logging.googleapis.com/spanId spanId מזהה הטווח בתוך המעקב שמשויך לרשומה ביומן. מידע נוסף זמין במאמר spanId בדף LogEntry. "logging.googleapis.com/spanId":"000000000000004a"
logging.googleapis.com/trace trace שם המשאב של ה-trace שמשויך לרשומה ביומן, אם יש כזה. מידע נוסף זמין במאמר trace בדף LogEntry. "logging.googleapis.com/trace":"projects/my-projectid/traces/0679686673a"

הערה: אם לא כותבים ל-stdout או ל-stderr, הערך של השדה הזה צריך להיות בפורמט projects/[PROJECT-ID]/traces/[TRACE-ID], כדי ש-Logs Explorer ומציג העקבות יוכלו להשתמש בו כדי לקבץ רשומות ביומן ולהציג אותן בשורה עם העקבות. אם autoformat_stackdriver_trace הוא true ו-[V] תואם לפורמט של ResourceTrace traceId הערך בשדה LogEntry trace הוא projects/[PROJECT-ID]/traces/[V].
logging.googleapis.com/trace_sampled traceSampled הערך בשדה הזה חייב להיות true או false. מידע נוסף זמין במאמר traceSampled בדף LogEntry. "logging.googleapis.com/trace_sampled": false

כדי ליצור רשומות ביומן בפורמט הפשוט, יוצרים ייצוג JSON של הרשומה באמצעות השדות. כל השדות הם אופציונליים.

הדוגמה הבאה היא של רשומה פשוטה ביומן בפורמט JSON:

{
  "severity":"ERROR",
  "message":"There was an error in the application.",
  "httpRequest":{
    "requestMethod":"GET"
  },
  "time":"2020-10-12T07:20:50.52Z",
  "logging.googleapis.com/insertId":"42",
  "logging.googleapis.com/labels":{
    "user_label_1":"value_1",
    "user_label_2":"value_2"
  },
  "logging.googleapis.com/operation":{
    "id":"get_data",
    "producer":"github.com/MyProject/MyApplication",
    "first":"true"
  },
  "logging.googleapis.com/sourceLocation":{
    "file":"get_data.py",
    "line":"142",
    "function":"getData"
  },
  "logging.googleapis.com/spanId":"000000000000004a",
  "logging.googleapis.com/trace":"projects/my-projectid/traces/06796866738c859f2f19b7cfb3214824",
  "logging.googleapis.com/trace_sampled":false
}

דוגמה לרשומה ביומן שמתקבלת:

{
  "insertId": "42",
  "jsonPayload": {
    "message": "There was an error in the application",
    "time": "2020-10-12T07:20:50.52Z"
  },
  "httpRequest": {
    "requestMethod": "GET"
  },
  "resource": {
    "type": "k8s_container",
    "labels": {
      "container_name": "hello-app",
      "pod_name": "helloworld-gke-6cfd6f4599-9wff8",
      "project_id": "stackdriver-sandbox-92334288",
      "namespace_name": "default",
      "location": "us-west4",
      "cluster_name": "helloworld-gke"
    }
  },
  "timestamp": "2020-10-12T07:20:50.52Z",
  "severity": "ERROR",
  "labels": {
    "user_label_2": "value_2",
    "user_label_1": "value_1"
  },
  "logName": "projects/stackdriver-sandbox-92334288/logs/stdout",
  "operation": {
    "id": "get_data",
    "producer": "github.com/MyProject/MyApplication",
    "first": true
  },
  "trace": "projects/my-projectid/traces/06796866738c859f2f19b7cfb3214824",
  "sourceLocation": {
    "file": "get_data.py",
    "line": "142",
    "function": "getData"
  },
  "receiveTimestamp": "2020-10-12T07:20:57.52Z",
  "spanId": "000000000000004a"
}

סוכן Logging: הגדרה

סוכן Logging מדור קודם, google-fluentd, הוא חבילה ספציפית ל-Cloud Logging של כלי לאיסוף נתוני יומן Fluentd. הסוכן Logging מגיע עם הגדרת ברירת המחדל של Fluentd, והוא משתמש בפלאגינים של Fluentd input כדי לשלוף יומני אירועים ממקורות חיצוניים, כמו קבצים בדיסק, או כדי לנתח רשומות יומן נכנסות.

ב-Fluentd יש רשימה של מנתחי נתונים נתמכים שמחלצים יומנים וממירים אותם למטענים ייעודיים (payloads) מובנים (JSON).

אם מגדירים מקור יומן עם format [PARSER_NAME], אפשר להשתמש במנתחי הנתונים המובנים ש-Fluentd מספקת. מידע על הגדרת סוכן Logging מדור קודם זמין במאמר הגדרת סוכן Logging.

בדוגמאות הקוד הבאות מוצגת ההגדרה של Fluentd, רשומת יומן הקלט ומטען הייעודי המובנה של הפלט, שהוא חלק מרשומה ביומן של Cloud Logging:

  • הגדרת Fluentd:

      <source>
        @type tail
    
        format syslog # This uses a predefined log format regex named
                      # `syslog`. See details at https://docs.fluentd.org/parser/syslog.
    
        path /var/log/syslog
        pos_file /var/lib/google-fluentd/pos/syslog.pos
        read_from_head true
        tag syslog
      </source>
    
  • רשומה ביומן (קלט):

      <6>Feb 28 12:00:00 192.168.0.1 fluentd[11111]: [error] Syslog test
    
  • מטען ייעודי (פלט) מובנה:

      jsonPayload: {
          "pri": "6",
          "host": "192.168.0.1",
          "ident": "fluentd",
          "pid": "11111",
          "message": "[error] Syslog test"
      }
    

מידע נוסף על אופן הפעולה של מנתח ה-syslog זמין במסמכי התיעוד המפורטים של Fluentd.

סוכן Logging: מנתחי נתונים רגילים מופעלים כברירת מחדל

הטבלה הבאה כוללת את מנתחי הנתונים הרגילים שנכללים בסוכן אם מפעילים רישום מובנה ביומן:

שם מנתח קובץ תצורה
syslog /etc/google-fluentd/config.d/syslog.conf
nginx /etc/google-fluentd/config.d/nginx.conf
apache2 /etc/google-fluentd/config.d/apache.conf
apache_error /etc/google-fluentd/config.d/apache.conf

הוראות להפעלת רישום מובנה ביומן במהלך ההתקנה של סוכן Logging מדור קודם מופיעות בקטע התקנה.

סוכן Logging: התקנה

כדי להפעיל רישום ביומן מובנה, צריך לשנות את הגדרת ברירת המחדל של סוכן Logging מדור קודם כשמתקינים או מתקינים מחדש את הסוכן. הפעלת רישום מובנה מחליפה את קובצי ההגדרות שצוינו קודם, אבל לא משנה את הפעולה של הסוכן עצמו.

כשמפעילים רישום מובנה ביומן, היומנים שמופיעים ברשימה מומרים לרשומות ביומן בפורמטים שונים מאלה שהיו להם לפני שהפעלתם רישום מובנה ביומן. אם היומנים מנותבים ליעדים מחוץ ל'רישום ביומן', השינוי עשוי להשפיע על כל אפליקציות העיבוד שלאחר מכן. לדוגמה, אם מעבירים יומנים ל-BigQuery, המערכת דוחה את רשומות היומן החדשות למשך שארית היום כי יש להן סכימה שגויה.

הוראות להתקנת סוכן Logging מדור קודם ולהפעלת רישום ביומן מובנה מופיעות במאמר התקנת סוכן Logging.

אפשר למצוא את קובצי התצורה של סוכן Logging במיקום /etc/google-fluentd/config.d/, שצריכים לכלול עכשיו את הנתחים הרגילים שמופעלים כברירת מחדל.

סוכן Logging: הגדרת פורמט של יומן גישה של Apache

כברירת מחדל, סוכן Logging מדור קודם שומר נתוני יומן גישה של Apache בשדה jsonPayload. לדוגמה:

{
  "logName": ...,
  "resource": ...,
  "httpRequest": ...,
  "jsonPayload": {
    "user"   : "some-user",
    "method" : "GET",
    "code"   : 200,
    "size"   : 777,
    "host"   : "192.168.0.1",
    "path"   : "/some-path",
    "referer": "some-referer",
    "agent"  : "Opera/12.0"
  },
  ...
}

לחלופין, אפשר להגדיר את סוכן Logging מדור קודם כדי לחלץ שדות מסוימים לשדה httpRequest. לדוגמה:

{
  "logName": ...,
  "resource": ...,
  "httpRequest": {
    "requestMethod": "GET",
    "requestUrl": "/some-path",
    "requestSize": "777",
    "status": "200",
    "userAgent": "Opera/12.0",
    "serverIp": "192.168.0.1",
    "referrer":"some-referrer",
  },
  "jsonPayload": {
    "user":"some-user"
  },
  ...
}

הגדרת השדה httpRequest, כמו בדוגמה הקודמת, עוזרת במעקב: במסוף Google Cloud מוצגים כל היומנים של בקשת HTTP נתונה בהיררכיה של הורה-צאצא.

כדי להגדיר את החילוץ הזה, מוסיפים את הקוד הבא לסוף התג /etc/google-fluentd/config.d/apache.conf:

<filter apache-access>
  @type record_transformer
  enable_ruby true
  <record>
    httpRequest ${ {"requestMethod" => record['method'], "requestUrl" => record['path'], "requestSize" => record['size'], "status" => record['code'], "userAgent" => record['agent'], "serverIp" => record['host'],
    "referer" => record['referer']} }
  </record>
  remove_keys method, path, size, code, agent, host, referer
</filter>

פרטים נוספים על הגדרת הרשומות ביומן זמינים במאמר שינוי רשומות ביומן.

סוכן Logging: הגדרת פורמט של יומן גישה ל-nginx

כברירת מחדל, סוכן Logging מדור קודם שומר את נתוני יומן הגישה של nginx בשדה jsonPayload. לדוגמה:

{
  "logName": ...,
  "resource": ...,
  "httpRequest": ...,
  "jsonPayload": {
    "remote":"127.0.0.1",
    "host":"192.168.0.1",
    "user":"some-user",
    "method":"GET",
    "path":"/some-path",
    "code":"200",
    "size":"777",
    "referrer":"some-referrer",
    "agent":"Opera/12.0",
    "http_x_forwarded_for":"192.168.3.3"
  },
  ...
}

לחלופין, אפשר להגדיר את סוכן Logging מדור קודם כדי לחלץ שדות מסוימים לשדה httpRequest. לדוגמה:

{
  "logName": ...,
  "resource": ...,
  "httpRequest": {
    "requestMethod": "GET",
    "requestUrl": "/some-path",
    "requestSize": "777",
    "status": "200",
    "userAgent": "Opera/12.0",
    "remoteIp": "127.0.0.1",
    "serverIp": "192.168.0.1",
    "referrer":"some-referrer",
  },
  "jsonPayload": {
    "user":"some-user",
    "http_x_forwarded_for":"192.168.3.3"
  },
  ...
}

הגדרת השדה httpRequest, כמו בדוגמה הקודמת, עוזרת במעקב: במסוף Google Cloud מוצגים כל הרישומים של בקשת HTTP נתונה בהיררכיה של הורה-צאצא.

כדי להגדיר את החילוץ הזה, מוסיפים את הקוד הבא לסוף התג /etc/google-fluentd/config.d/nginx.conf:

<filter nginx-access>
  @type record_transformer
  enable_ruby true
  <record>
    httpRequest ${ {"requestMethod" => record['method'], "requestUrl" => record['path'], "requestSize" => record['size'], "status" => record['code'], "userAgent" => record['agent'], "remoteIp" => record['remote'], "serverIp" => record['host'], "referer" => record['referer']} }
  </record>
  remove_keys method, path, size, code, agent, remote, host, referer
</filter>

פרטים נוספים על הגדרת הרשומות ביומן זמינים במאמר שינוי רשומות ביומן.

כתיבת מנתח משלכם

אם הקבצים שלכם לא נתמכים על ידי מנתחי הנתונים הרגילים, אתם יכולים לכתוב מנתח נתונים משלכם. מנתחי הנתונים מורכבים מביטוי רגולרי שמשמש להתאמה של רשומות ביומן ולהוספת תוויות לחלקים.

בדוגמאות הקוד הבאות מוצגת שורה ביומן ברשומה ביומן, הגדרה עם ביטוי רגולרי שמציין את הפורמט של השורה ביומן והרשומה ביומן שמאוחסנת:

  • שורה ביומן ברשומה ביומן:

    REPAIR CAR $500
    
  • הגדרה עם ביטוי רגולרי שמציין את הפורמט של שורת היומן:

    $ sudo vim /etc/google-fluentd/config.d/test-structured-log.conf
    $ cat /etc/google-fluentd/config.d/test-structured-log.conf
    <source>
      @type tail
    
      # Format indicates the log should be translated from text to
      # structured (JSON) with three fields, "action", "thing" and "cost",
      # using the following regex:
      format /(?<action>\w+) (?<thing>\w+) \$(?<cost>\d+)/
      # The path of the log file.
      path /tmp/test-structured-log.log
      # The path of the position file that records where in the log file
      # we have processed already. This is useful when the agent
      # restarts.
      pos_file /var/lib/google-fluentd/pos/test-structured-log.pos
      read_from_head true
      # The log tag for this log input.
      tag structured-log
    </source>
    
  • רשומה ביומן שמתקבלת:

    {
    insertId:  "eps2n7g1hq99qp"
    jsonPayload: {
      "action": "REPAIR"
      "thing": "CAR"
      "cost": "500"
    }
    labels: {
      compute.googleapis.com/resource_name:  "add-structured-log-resource"
    }
    logName:  "projects/my-sample-project-12345/logs/structured-log"
    receiveTimestamp:  "2023-03-21T01:47:11.475065313Z"
    resource: {
      labels: {
        instance_id:  "3914079432219560274"
        project_id:  "my-sample-project-12345"
        zone:  "us-central1-c"
      }
      type:  "gce_instance"
    }
    timestamp:  "2023-03-21T01:47:05.051902169Z"
    }
    

פתרון בעיות

כדי לפתור בעיות נפוצות שקשורות להתקנה או לאינטראקציה עם סוכן Logging מדור קודם, אפשר לעיין במאמר פתרון בעיות בסוכן.

המאמרים הבאים