ส่ง Structured Logging จาก Cloud Run ไปที่ Cloud Logging

Weerasak Chongnguluam
CJ Express Tech (TILDI)
2 min readSep 24, 2022

ถ้าเรารันเซอร์วิสของเราบน GCP Cloud Run ซึ่งเป็น Knative platform ของ GCP เรื่องการจัดการ Log เราจะง่ายมากๆเลย ถ้าเราใช้ Cloud Logging ของ GCP ร่วมด้วย แต่ถ้าเราอยากส่งในแบบ structured logging ก็มี format ที่เราต้องรู้เผื่อช่วยให้ Cloud Logging จัดเก็บข้อมูลเราได้ถูกที่ถูกทาง โพสต์นี้เราจะอธิบาย field พิเศษที่เมื่อเราเขียน Log ลงไปแล้ว Cloud Logging agent และ Cloud Run จะจัดรูปร่างหน้าตาให้ก่อนส่งไปให้ Cloud Logging ว่ามีอะไรบ้าง

ก่อนอื่นต้องรู้ก่อนว่าสิ่งที่ Cloud Run จะส่ง log ไปให้ Cloud Logging อัตโนมัติได้แก่

  • Request access logging เมื่อเรารัน http service บน Cloud Run แล้วมี request มาที่ service ของเรา Cloud Run จะสร้าง Request access logging ให้เราอัตโนมัติ ดังนั้นเราไม่ต้องเขียน log แบบนี้เองที่ service

ส่วนใน service เรานั้นถ้าเราต้องการให้ Cloud Run จัดส่ง log ไปให้ เราแค่เขียนข้อมูลออกไปได้ทางช่องทางต่อไปนี้

  • เขียนออก Standard Output
  • เขียนออก Standard Error
  • เขียนลงไฟล์ที่ path /var/log
  • ผ่าน syslog (dev/log )

ถ้า log ที่เราเขียนออกไปเป็นแค่ข้อมูลธรรมดา เวลาถูกส่งไปก็จะเอาไปไว้ใน field textPayload แต่ถ้าเป็น JSON ก็จะถูกส่งไปไว้ใน jsonPayload

ตัวอย่าง structured log ที่เราสามารถส่งไปได้เช่น

{
"message": "before call api"
}

แต่เมื่อ logging agent เจอ log ของเราก็จะแปลงให้อยู่ในรูปแบบของ LogEntry ของ Cloud Logging แบบนี้ให้

{
"insertId": "68dcb56efd46632e6a420008",
"jsonPayload": {
"message": "before call api"
},
"resource": {
"type": "cloud_run_revision",
"labels": {
"project_id": "example-project",
"location": "asia-southeast1",
"service_name": "example-api",
"configuration_name": "example-api",
"revision_name": "example-api-00107-xyz"
}
},
"timestamp": "2022-09-24T02:24:02.551132Z",
"severity": "DEFAULT",
"labels": {
"instanceId": "5e590743b327c074694882e51af18af66b9a8ba37aa0b5c6fd0f8bab20ed7a82ef565db0001c9ea28bd4a2e80a93812a6cc070556d59636daa2b914640bfc0f1433d73"
},
"logName": "projects/example-project/logs/run.googleapis.com%2Fstderr",
"receiveTimestamp": "2022-09-24T02:24:02.556546346Z",
}

จะเห็นว่าเอา JSON ที่เราเขียนลงไป ไปอยู่ใน jsonPayload แล้วก็เติมข้อมูลในส่วนของ insertId , resource.type , resource.labels.[project_id, location, service_name, configuration_name, revision_name] , timestamp , severity , labels.instanceId , logName , receiveTimestamp ให้เราเอง

ในส่วนของ resource.type , resource.labels.[project_id, location, service_name, configuration_name, revision_name] , logName , receiveTimestamp เราแก้ไขไม่ได้ Cloud Run จะเติมให้เอง แต่เราสามารถปรับข้อมูลอื่นๆของ LogEntry โดยส่ง JSON field ที่แมปกับ LogEntry ของ Cloud Logging ตาม document นี้ของ Cloud Logging https://cloud.google.com/logging/docs/structured-logging#special-payload-fields

ตัวอย่างเช่นถ้าเราอยากปรับ severity เป็น ERROR เราก็ใช้ field name "severity" เป็นค่า "ERROR" ได้เลย

แต่ถ้าเราอยากแปะ trace id เข้าไปกับ log เพื่อ เชื่อมโยง log กับ trace ของ request ด้วยก็ให้เพิ่มที่ field name logging.googleapis.com/trace

ตัวอย่างเช่น

{
"message": "call api error",
"severity": "ERROR",
"logging.googleapis.com/trace": "projects/example-project/traces/802d43d052c8d19924b565e8ab6314a3"
}

ซึ่งก็จะถูก agent แปลงไปเป็น LogEntry แบบนี้

{
"insertId": "68dcb56efd46632e6a420008",
"jsonPayload": {
"message": "call api error"
},
"resource": {
"type": "cloud_run_revision",
"labels": {
"project_id": "example-project",
"location": "asia-southeast1",
"service_name": "example-api",
"configuration_name": "example-api",
"revision_name": "example-api-00107-xyz"
}
},
"timestamp": "2022-09-24T02:24:02.551132Z",
"severity": "ERROR",
"labels": {
"instanceId": "5e590743b327c074694882e51af18af66b9a8ba37aa0b5c6fd0f8bab20ed7a82ef565db0001c9ea28bd4a2e80a93812a6cc070556d59636daa2b914640bfc0f1433d73"
},
"logName": "projects/example-project/logs/run.googleapis.com%2Fstderr",
"trace": "projects/example-project/traces/802d43d052c8d19924b565e8ab6314a3",
"receiveTimestamp": "2022-09-24T02:24:02.556546346Z",
}

สุดท้าย แล้วเราจะได้ค่า trace id ของ request มาได้ยังไง

เราสามารถแกะ trace id มาได้จาก http header ที่ชื่อว่า X-Cloud-Trace-Context โดย format ของ header จะเป็นแบบนี้

"X-Cloud-Trace-Context: TRACE_ID/SPAN_ID;o=TRACE_TRUE"

ถ้าสนใจแค่ trace id ก็แค่ parse ค่าแรกก่อน slash มาได้เลย

References

Cloud Run Logging: https://cloud.google.com/run/docs/logging

Cloud Logging Strucutured Logging: https://cloud.google.com/logging/docs/structured-logging

--

--