在 Knative serving 中記錄及查看記錄

本頁面說明使用 Knative Serving 時可用的記錄,以及記錄的查看與寫入方式。

Knative serving 有兩種類型的記錄:

  • 要求記錄:傳送到 Knative serving 服務的要求記錄,這類的記錄是自動建立的。
  • 容器記錄:容器執行個體發出的記錄,通常是來自您自己的程式碼,這類的記錄會寫入支援的位置,如寫入容器記錄所述。

啟用記錄

Google Cloud 記錄檔會自動傳送至 Cloud Logging。如果是 Google Distributed Cloud,必須先啟用記錄檔

查看記錄

有幾種方式可以查看您的服務記錄:

  • 使用 Google Cloud 控制台中的 Knative serving 頁面
  • 在 Google Cloud 控制台中使用 Cloud Logging Logs Explorer。

這兩種查看方式所看到的記錄相同,都儲存在 Cloud Logging 中,但 Cloud Logging 的 Logs Explorer 提供更多詳細資料和更多的篩選功能。

在 Knative serving 中查看記錄

如要在 Knative serving 頁面查看記錄:

  1. 前往 Knative serving

  2. 在顯示的清單中按一下所要的服務。

  3. 按一下 [LOGS] (記錄) 分頁標籤,取得此服務所有修訂版本的要求和容器記錄。您可以依記錄的嚴重性等級進行篩選。

在 Cloud Logging 中查看記錄

如要在 Cloud Logging Logs Explorer 中查看 Knative serving 記錄,請按照下列步驟操作:

  1. 前往Google Cloud 控制台的「Logs Explorer」頁面。

  2. 在頁面頂端選取現有 Google Cloud 專案,或建立新專案。

  3. 使用下拉式選單選取資源:Kubernetes 容器

詳情請參閱「使用 Logs Explorer」。

在 Cloud Code 中查看記錄

如要在 Cloud Code 中查看記錄,請參閱 IntelliJVisual Studio Code 指南。

以程式輔助方式讀取記錄

如要以程式輔助方式讀取記錄,可以使用下列其中一種方法:

寫入容器記錄

當您寫入服務的記錄時,只要將記錄寫入以下任一位置,Cloud Logging 就會自動收集記錄:

多數開發人員應使用標準輸出和標準錯誤來寫入記錄。

寫入這些支援位置的容器記錄會自動與 Knative serving 服務、修訂版本和位置建立關聯。

使用簡單文字與結構化 JSON 記錄

當您寫入記錄時,您可以傳送簡易文字字串或傳送一行序列化 JSON (又稱為「結構化」資料)。Cloud Logging 會擷取並剖析這項資料,然後置於 jsonPayload 中,簡易文字訊息則置於 textPayload

寫入結構化記錄檔

下列程式碼片段說明如何寫入結構化記錄項目。並說明如何將記錄訊息與對應的要求記錄建立關聯。

Node.js


// Uncomment and populate this variable in your code:
// const project = 'The project ID of your function or Cloud Run service';

// Build structured log messages as an object.
const globalLogFields = {};

// Add log correlation to nest all log messages beneath request log in Log Viewer.
// (This only works for HTTP-based invocations where `req` is defined.)
if (typeof req !== 'undefined') {
  const traceHeader = req.header('X-Cloud-Trace-Context');
  if (traceHeader && project) {
    const [trace] = traceHeader.split('/');
    globalLogFields['logging.googleapis.com/trace'] =
      `projects/${project}/traces/${trace}`;
  }
}

// Complete a structured log entry.
const entry = Object.assign(
  {
    severity: 'NOTICE',
    message: 'This is the default display field.',
    // Log viewer accesses 'component' as 'jsonPayload.component'.
    component: 'arbitrary-property',
  },
  globalLogFields
);

// Serialize to a JSON string and output.
console.log(JSON.stringify(entry));

Python

# Uncomment and populate this variable in your code:
# PROJECT = 'The project ID of your Cloud Run service';

# Build structured log messages as an object.
global_log_fields = {}

# Add log correlation to nest all log messages.
# This is only relevant in HTTP-based contexts, and is ignored elsewhere.
# (In particular, non-HTTP-based Cloud Functions.)
request_is_defined = "request" in globals() or "request" in locals()
if request_is_defined and request:
    trace_header = request.headers.get("X-Cloud-Trace-Context")

    if trace_header and PROJECT:
        trace = trace_header.split("/")
        global_log_fields[
            "logging.googleapis.com/trace"
        ] = f"projects/{PROJECT}/traces/{trace[0]}"

# Complete a structured log entry.
entry = dict(
    severity="NOTICE",
    message="This is the default display field.",
    # Log viewer accesses 'component' as jsonPayload.component'.
    component="arbitrary-property",
    **global_log_fields,
)

print(json.dumps(entry))

Go

每個記錄項目的結構都由 Entry 類型提供:


// Entry defines a log entry.
type Entry struct {
	Message  string `json:"message"`
	Severity string `json:"severity,omitempty"`
	Trace    string `json:"logging.googleapis.com/trace,omitempty"`

	// Logs Explorer allows filtering and display of this as `jsonPayload.component`.
	Component string `json:"component,omitempty"`
}

// String renders an entry structure to the JSON format expected by Cloud Logging.
func (e Entry) String() string {
	if e.Severity == "" {
		e.Severity = "INFO"
	}
	out, err := json.Marshal(e)
	if err != nil {
		log.Printf("json.Marshal: %v", err)
	}
	return string(out)
}

記錄 Entry struct 時,系統會呼叫 String 方法,將其封送至 Cloud Logging 預期的 JSON 格式:


func init() {
	// Disable log prefixes such as the default timestamp.
	// Prefix text prevents the message from being parsed as JSON.
	// A timestamp is added when shipping logs to Cloud Logging.
	log.SetFlags(0)
}

func indexHandler(w http.ResponseWriter, r *http.Request) {
	// Uncomment and populate this variable in your code:
	// projectID = "The project ID of your Cloud Run service"

	// Derive the traceID associated with the current request.
	var trace string
	if projectID != "" {
		traceHeader := r.Header.Get("X-Cloud-Trace-Context")
		traceParts := strings.Split(traceHeader, "/")
		if len(traceParts) > 0 && len(traceParts[0]) > 0 {
			trace = fmt.Sprintf("projects/%s/traces/%s", projectID, traceParts[0])
		}
	}

	log.Println(Entry{
		Severity:  "NOTICE",
		Message:   "This is the default display field.",
		Component: "arbitrary-property",
		Trace:     trace,
	})

	fmt.Fprintln(w, "Hello Logger!")
}

Java

如要啟用 JSON 記錄功能,請在 logback.xml 設定中啟用 Logstash JSON 編碼器,並搭配 LogbackSLF4J 使用。

// Build structured log messages as an object.
Object globalLogFields = null;

// Add log correlation to nest all log messages beneath request log in Log Viewer.
// TODO(developer): delete this code if you're creating a Cloud
//                  Function and it is *NOT* triggered by HTTP.
String traceHeader = req.headers("x-cloud-trace-context");
if (traceHeader != null && project != null) {
  String trace = traceHeader.split("/")[0];
  globalLogFields =
      kv(
          "logging.googleapis.com/trace",
          String.format("projects/%s/traces/%s", project, trace));
}
// -- End log correlation code --

// Create a structured log entry using key value pairs.
// For instantiating the "logger" variable, see
// https://cloud.google.com/run/docs/logging#run_manual_logging-java
logger.error(
    "This is the default display field.",
    kv("component", "arbitrary-property"),
    kv("severity", "NOTICE"),
    globalLogFields);
<configuration>
  <appender name="jsonConsoleAppender" class="ch.qos.logback.core.ConsoleAppender">
    <encoder class="net.logstash.logback.encoder.LogstashEncoder">
      <!-- Ignore default logging fields -->
      <fieldNames>
        <timestamp>[ignore]</timestamp>
        <version>[ignore]</version>
        <logger>[ignore]</logger>
        <thread>[ignore]</thread>
        <level>[ignore]</level>
        <levelValue>[ignore]</levelValue>
      </fieldNames>
    </encoder>
  </appender>
  <root level="INFO">
    <appender-ref ref="jsonConsoleAppender"/>
  </root>
</configuration>

訊息中的特殊 JSON 欄位

特殊欄位的說明文件所述,當您以 JSON 目錄的形式提供結構化記錄時,系統會從 jsonPayload 去除某些特殊欄位,然後寫入產生的 LogEntry 中的對應欄位。

舉例來說,如果 JSON 含有 severity 屬性,系統會從 jsonPayload 將其移除,並改以記錄項目的 severity 形式顯示。如果存在 message 屬性,則會用作記錄項目的主要顯示文字。 如要進一步瞭解特殊屬性,請參閱下方的「記錄資源」一節。

建立容器記錄與要求記錄間的關聯

在 Logs Explorer 中,以相同 trace 關聯的記錄可用「父子關係」格式來查看:當您按一下要求記錄項目左側的三角形圖示,就會以巢狀方式,在要求記錄下方顯示與該要求相關的容器記錄。

除非您使用 Cloud Logging 用戶端程式庫,否則容器記錄不會自動與要求記錄產生關聯,。如要在不使用用戶端程式庫的情況下,將容器記錄與要求記錄建立關聯,可以使用包含 logging.googleapis.com/trace 欄位的結構化 JSON 記錄行,這個欄位會顯示從 X-Cloud-Trace-Context 標頭擷取的追蹤 ID,如結構化記錄的上述範例所示。

控管要求記錄的資源使用量

要求記錄會自動建立。雖然您無法直接從 Knative serving 控管要求記錄的數量,但您可以利用 Cloud Logging 的排除記錄功能。

Logging 代理程式注意事項

如果您曾搭配使用 Cloud Logging 與特定 Google Cloud 產品 (例如 Compute Engine),可能已使用 Cloud Logging 記錄代理程式。Knative serving 內建記錄收集功能,因此不需要使用記錄代理程式。

記錄資源

按一下 Logs Explorer 中的記錄項目,開啟 JSON 格式的記錄項目,以便深入查看您要的詳細資料。

記錄項目說明文件所述,一個記錄項目中的所有欄位,例如時間戳記、嚴重性和 httpRequest 等,都是標準內容。

不過,有些標籤或資源標籤則專屬於 Knative serving。這裡列出使用範例內容的標籤:

{
 httpRequest: {}
 insertId:  "5c82b3d1000ece0000000000"
 labels: {
  instanceId:  "00bf4bf00000fb59c906a00000c9e29c2c4e06dce91500000000056008d2b6460f163c0057b97b2345f2725fb2423ee5f0bafd36df887fdb1122371563cf1ff453717282afe000001"
 }
 logName:  "projects/my-project/logs/kubernetes-engine/enterprise/knative-serving/.googleapis.com%2Frequests"
 receiveTimestamp:  "2019-03-08T18:26:25.981686167Z"
 resource: {
  labels: {
   configuration_name:  "myservice"
   location:  "us-central1"
   project_id:  "my-project"
   revision_name:  "myservice-00002"
   service_name:  "myservice"
  }
  type:  "cloud_run_revision"
 }
 severity:  "INFO"
 timestamp:  "2019-03-08T18:26:25.970397Z"
}
欄位 值和備註
instanceId 處理要求的容器執行個體。
logName 識別記錄,例如要求記錄、標準錯誤、標準輸出等。
configuration_name 建立處理要求之修訂版本的「設定」資源。
location 識別服務的 GCP 位置。
project_id 部署服務的專案。
revision_name 處理要求的修訂版本。
service_name 處理要求的服務。
type cloud_run_revision。Knative serving 資源類型。