רישום וצפייה ביומנים ב-Knative serving

בדף הזה מוסבר על היומנים שזמינים כשמשתמשים ב-Knative serving, ואיך צופים ביומנים וכותבים אותם.

ב-Knative Serving יש שני סוגים של יומנים:

  • יומני בקשות: יומנים של בקשות שנשלחו לשירותים של Knative serving. היומנים האלה נוצרים באופן אוטומטי.
  • יומני קונטיינר: יומנים שנוצרים ממופעי הקונטיינר, בדרך כלל מהקוד שלכם, ונכתבים במיקומים נתמכים כפי שמתואר במאמר כתיבת יומני קונטיינר.

הפעלת יומנים

יומני Google Cloud נשלחים אוטומטית אל Cloud Logging. ב-Google Distributed Cloud, קודם צריך להפעיל את היומנים.

צפייה ביומנים

יש כמה דרכים לצפייה ביומנים של השירות:

  • בדף Knative serving במסוף Google Cloud
  • משתמשים ב-Logs Explorer של Cloud Logging במסוף Google Cloud .

בשתי השיטות האלה מוצגים אותם יומנים שמאוחסנים ב-Cloud Logging, אבל בכלי Logs Explorer של Cloud Logging יש יותר פרטים ויכולות סינון.

צפייה ביומנים במילוי בקשות מסוג Knative

כדי להציג יומנים בדף של Knative serving:

  1. מעבר אל Knative serving

  2. לוחצים על השירות הרצוי ברשימה שמוצגת.

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

צפייה ביומנים ב-Cloud Logging

כדי לראות את יומני Knative Serving ב-Logs Explorer של Cloud Logging:

  1. נכנסים לדף Logs Explorer במסוףGoogle Cloud .

  2. בוחרים פרויקט קיים Google Cloud בחלק העליון של הדף או יוצרים פרויקט חדש.

  3. בתפריטים הנפתחים, בוחרים את המשאב: Kubernetes Container.

מידע נוסף זמין במאמר שימוש ב-Logs Explorer.

צפייה ביומנים ב-Cloud Code

כדי לראות את היומנים ב-Cloud Code, אפשר לקרוא את המדריכים ל-IntelliJ ול-Visual 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, מתבצעת קריאה לשיטה String כדי להמיר אותו לפורמט JSON שצפוי ב-Cloud Logging:


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 ו-SLF4J, צריך להפעיל את Logstash JSON Encoder בהגדרות של logback.xml.

// 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. כדי לבצע קורלציה בין יומני קונטיינרים לבין יומני בקשות בלי להשתמש בספריית לקוח, אפשר להשתמש בשורת יומן JSON מובנית שמכילה שדה logging.googleapis.com/trace עם מזהה המעקב שחולץ מהכותרת X-Cloud-Trace-Context, כמו בדוגמה שלמעלה לרישום מובנה ביומן.

שליטה בשימוש במשאבים ביומן הבקשות

יומני בקשות נוצרים באופן אוטומטי. למרות שאי אפשר לשלוט בכמות של יומני הבקשות ישירות מ-Knative serving, אפשר להשתמש בתכונה החרגת יומנים מ-Cloud Logging.

הערה לגבי רישום נציגים ביומן

אם השתמשתם ב-Cloud Logging עם מוצרים מסוימים, כמו Compute Engine, יכול להיות שהשתמשתם בסוכני רישום ב-Cloud Logging. Google Cloud ב-Knative Serving לא נעשה שימוש בסוכני רישום ביומן כי יש לו תמיכה מובנית באיסוף יומנים.

משאב Logging

כשלוחצים על רשומה ביומן ב-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.