Strukturiertes Logging

In diesem Dokument werden das Konzept des strukturierten Loggings und die Methoden zum Strukturieren von Nutzlastfeldern von Logeinträgen erläutert. Wenn die Lognutzlast als JSON-Objekt formatiert und das Objekt im Feld jsonPayload gespeichert ist, wird der Logeintrag als strukturiertes Log bezeichnet. Für diese Logs können Sie Abfragen erstellen, die bestimmte JSON-Pfade durchsuchen, und bestimmte Felder in der Lognutzlast indexieren. Wenn dagegen die Lognutzlast als String formatiert und im Feld textPayload gespeichert ist, ist der Logeintrag unstrukturiert. Sie können im Textfeld suchen, aber den Inhalt nicht indexieren.

So erstellen Sie strukturierte Logeinträge:

  • Rufen Sie die API-Methode entries.write auf und geben Sie eine vollständig formatierte LogEntry an.
  • Verwenden Sie eine Cloud Logging-Clientbibliothek, die strukturierte Logs schreibt.
  • Führen Sie den Befehl gcloud logging write aus.
  • Verwenden Sie den BindPlane-Dienst.
  • Verwenden Sie einen Agent zum Schreiben von Protokollen:

    • Einige Google Cloud-Dienste enthalten einen integrierten Logging-Agent, der die in stdout oder stderr geschriebenen Daten als Logs an Cloud Logging sendet. Sie können diesen Ansatz für Google Cloud-Dienste wie Google Kubernetes Engine, die flexible App Engine-Umgebung und Cloud Functions verwenden.

    • Bei virtuellen Compute Engine-Maschinen (VMs) können Sie den Ops-Agent oder den Legacy-Logging-Agent installieren und konfigurieren und dann den installierten Agent verwenden, um Logs an Cloud Logging zu senden.

Weitere Informationen zu diesen Ansätzen finden Sie in den folgenden Abschnitten.

Logs mit Clientbibliotheken oder der API schreiben

Sie können Logdaten mit den Cloud Logging-Clientbibliotheken, die die Cloud Logging API aufrufen, oder direkt durch Aufrufen der Cloud Logging API schreiben. Clientbibliotheken können das Ausfüllen der speziellen JSON-Felder vereinfachen, indem sie einige Informationen automatisch erfassen und Schnittstellen bereitstellen, um die Felder entsprechend zu füllen. Für volle Kontrolle über die Struktur der Nutzlasten können Sie jedoch die Cloud Logging API direkt aufrufen und die vollständige LogEntry-Struktur an die Cloud Logging API übergeben.

Weitere Informationen finden Sie in der Referenz zu entries.write.

Codebeispiele finden Sie unter Strukturierte Logs schreiben.

Logs über die gcloud CLI schreiben

Sie können Logdaten über die gcloud CLI schreiben. Die Benutzeroberfläche unterstützt unstrukturierte und strukturierte Logs. Wenn Sie ein strukturiertes Log schreiben möchten, geben Sie dem Befehl ein serielles JSON-Objekt an.

Eine Kurzanleitung finden Sie unter Logeinträge mit der Google Cloud CLI schreiben und abfragen.

Codebeispiele finden Sie in der Referenz zu gcloud logging write.

Logs mit BindPlane schreiben

Mit dem BindPlane-Dienst können Sie Logs an Logging senden. Bei diesen Logs liegen die Nutzlasten im JSON-Format vor und sind gemäß dem Quellsystem strukturiert. Informationen zum Suchen und Aufrufen von Logs, die mit BindPlane aufgenommen wurden, finden Sie in der Kurzanleitung für BindPlane.

Logs mit einem Agent schreiben

Sie können Logs von Ihren Compute Engine-Instanzen mit dem Ops-Agent oder dem Legacy-Cloud Logging-Agent abrufen. Beide Agents können Messwerte aus Drittanbieteranwendungen erfassen und unterstützen strukturiertes Logging:

  • Der Ops-Agent ist der empfohlene Agent zum Erfassen von Telemetriedaten aus Ihren Compute Engine-Instanzen. Dieser Agent kombiniert Logging und Messwerte in einem einzigen Agent, bietet eine YAML-basierte Konfiguration und Logging mit hohem Durchsatz.

    Informationen zum Konfigurieren des Ops-Agents für die Unterstützung von strukturiertem Logging oder zum Anpassen der Form eines strukturierten Logs finden Sie unter Ops-Agent konfigurieren.

  • Der Legacy-Cloud Logging-Agent erfasst Logs. Dieser Agent erfasst keine anderen Formen von Telemetrie.

Der Rest dieses Abschnitts bezieht sich speziell auf den Legacy-Logging-Agent.

Logging-Agent: spezielle JSON-Felder

Einige Felder im JSON-Objekt werden vom Legacy-Logging-Agent als speziell erkannt und in die LogEntry-Struktur extrahiert. Mit diesen speziellen JSON-Feldern können die folgenden Felder im LogEntry festgelegt werden:

  • severity
  • spanId
  • labels (vom Nutzer definiert)
  • httpRequest

Da JSON genauer und vielseitiger als Textzeilen ist, können Sie JSON-Objekte verwenden, um mehrzeilige Nachrichten zu schreiben und Metadaten hinzuzufügen.

In der folgenden Tabelle sind die Felder und ihre Werte im JSON-Format aufgeführt, um strukturierte Logeinträge für Ihre Anwendungen mit dem vereinfachten Format zu erstellen:

JSON-Logfeld LogEntry Feld Cloud Logging-Agent-Funktion Beispielwert
severity severity Der Logging-Agent versucht, eine Übereinstimmung mit einer Vielzahl von allgemeinen Schweregrad-Strings zu finden. Dazu gehört die Liste der LogSeverity-Strings, die von der Logging API erkannt werden. "severity":"ERROR"
message textPayload (oder Teil von jsonPayload) Die Nachricht, die in der Logeintragszeile im Log-Explorer angezeigt wird. "message":"There was an error in the application."

Hinweis: message wird als textPayload gespeichert, wenn es das einzige verbleibende Feld ist, nachdem der Logging-Agent die anderen Spezialfelder verschoben hat und detect_json nicht aktiviert war. Andernfalls bleibt message in jsonPayload. detect_json gilt nicht für verwaltete Logging-Umgebungen wie Google Kubernetes Engine. Wenn Ihr Logeintrag einen Ausnahme-Stacktrace enthält, sollte dieser im JSON-Logfeld message festgelegt werden, damit er geparst und in Error Reporting gespeichert werden kann.
log (nur Legacy-Google Kubernetes Engine) textPayload Gilt nur für Legacy-Google Kubernetes Engine: Wenn nach dem Verschieben von Feldern für spezielle Zwecke nur ein log-Feld bleibt, wird dieses Feld als textPayload gespeichert.
httpRequest httpRequest Ein strukturierter Datensatz im Format des Felds LogEntry HttpRequest. "httpRequest":{"requestMethod":"GET"}
zeitbezogene Felder timestamp Weitere Informationen finden Sie unter Zeitbezogene Felder. "time":"2020-10-12T07:20:50.52Z"
logging.googleapis.com/insertId insertId Weitere Informationen finden Sie unter insertId auf der LogEntry-Seite. "logging.googleapis.com/insertId":"42"
logging.googleapis.com/labels labels Der Wert dieses Felds muss ein strukturierter Datensatz sein. Weitere Informationen finden Sie unter labels auf der LogEntry-Seite. "logging.googleapis.com/labels": {"user_label_1":"value_1","user_label_2":"value_2"}
logging.googleapis.com/operation operation Der Wert dieses Felds wird auch vom Log-Explorer verwendet, um zugehörige Logeinträge zu gruppieren. Weitere Informationen finden Sie auf der LogEntry-Seite unter operation. "logging.googleapis.com/operation": {"id":"get_data","producer":"github.com/MyProject/MyApplication", "first":"true"}
logging.googleapis.com/sourceLocation sourceLocation Speicherort des Quellcodes-Informationen zum Logeintrag, falls vorhanden. Weitere Informationen finden Sie unter LogEntrySourceLocation auf der LogEntry-Seite. "logging.googleapis.com/sourceLocation": {"file":"get_data.py","line":"142","function":"getData"}
logging.googleapis.com/spanId spanId Die Span-ID innerhalb des Trace, das mit dem Logeintrag verknüpft ist. Weitere Informationen finden Sie unter spanId auf der LogEntry-Seite. "logging.googleapis.com/spanId":"000000000000004a"
logging.googleapis.com/trace trace Der Ressourcenname des mit dem Logeintrag verknüpften Trace, falls vorhanden. Weitere Informationen finden Sie unter trace auf der LogEntry-Seite. "logging.googleapis.com/trace":"projects/my-projectid/traces/0679686673a"

Hinweis: Wenn nicht in stdout oder stderr geschrieben wird, sollte der Wert dieses Felds als projects/[PROJECT-ID]/traces/[TRACE-ID] formatiert werden, damit er vom Log Explorer und vom Trace Viewer verwendet werden kann, um Logeinträge zu gruppieren und sie im Einklang mit Traces anzuzeigen. Wenn autoformat_stackdriver_trace wahr ist und [V] dem Format des ResourceTrace traceId entspricht, hat das LogEntry-Feld trace den Wert projects/[PROJECT-ID]/traces/[V].
logging.googleapis.com/trace_sampled traceSampled Der Wert dieses Felds muss true oder false sein. Weitere Informationen finden Sie unter traceSampled auf der LogEntry-Seite. "logging.googleapis.com/trace_sampled": false

Zum Erstellen von Logeinträgen im vereinfachten Format müssen Sie eine JSON-Darstellung des Eintrags mithilfe der Felder erstellen. Alle Felder sind optional.

Im Folgenden finden Sie ein Beispiel für einen vereinfachten JSON-Logeintrag:

{
  "severity":"ERROR",
  "message":"There was an error in the application.",
  "httpRequest":{
    "requestMethod":"GET"
  },
  "times":"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
}

Dies ist ein Beispiel für den resultierenden Logeintrag:

{
  "insertId": "42",
  "jsonPayload": {
    "message": "There was an error in the application",
    "times": "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-11-07T15:57:35.945508391Z",
  "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-11-07T15:57:42.411414059Z",
  "spanId": "000000000000004a"
}

Logging-Agent: Konfiguration

Der Legacy-Logging-Agent google-fluentd ist ein Cloud Logging-spezifisches Paket des Logdaten-Collectors Geocoding. Der Logging-Agent verwendet die Fluentd-Standardkonfiguration und die Eingabe-Plugins von Fluentd, um Ereignislogs aus externen Quellen wie Dateien auf der Festplatte abzurufen oder um eingehende Logdatensätze zu analysieren.

Für Fluentd gibt es verschiedene unterstützte Parser, die Logs extrahieren und in strukturierte (JSON-)Nutzlasten konvertieren.

Wenn Sie eine Logquelle mit format [PARSER_NAME] konfigurieren, können Sie auf den integrierten Parsern von GTFS aufbauen. Informationen zum Konfigurieren des Legacy-Logging-Agents finden Sie unter Logging-Agent konfigurieren.

Die folgenden Codebeispiele zeigen die Fluentd-Konfiguration, den Eingangslogdatensatz und die Ausgabe der strukturierten Nutzlast, die Teil eines Cloud Logging-Logeintrags ist:

  • Fluentd-Konfiguration:

      <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>
    
  • Logdatensatz (Eingabe):

      <6>Feb 28 12:00:00 192.168.0.1 fluentd[11111]: [error] Syslog test
    
  • Strukturierte Nutzlast (Ausgabe):

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

Weitere Informationen zur Funktionsweise des Parsers syslog finden Sie in der ausführlichen Dokumentation zu Fluentd.

Logging-Agent: Standardparser sind standardmäßig aktiviert

Die folgende Tabelle enthält die Standardparser, die im Agent enthalten sind, wenn Sie das strukturierte Logging aktivieren:

Parsername Konfigurationsdatei
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

Eine Anleitung zum Aktivieren des strukturierten Loggings beim Installieren des Legacy-Logging-Agents finden Sie im Abschnitt Installation.

Logging-Agent: Installation

Zum Aktivieren des strukturierten Loggings müssen Sie die Standardkonfiguration des Legacy-Logging-Agent bei der Installation oder Neuinstallation ändern. Wenn Sie das strukturierte Logging aktivieren, werden die zuvor aufgeführten Konfigurationsdateien ersetzt, die Funktionsweise des Agents selbst ändert sich jedoch nicht.

Wenn Sie das strukturierte Logging aktivieren, werden die aufgelisteten Logs in Logeinträge mit anderen Formaten als vor der Aktivierung strukturierter Logs umgewandelt. Wenn die Logs an Ziele außerhalb von Logging weitergeleitet werden, kann sich die Änderung auf alle Nachbearbeitungsanwendungen auswirken. Beim Routing von Logs an BigQuery beispielsweise lehnt BigQuery die neuen Logeinträge für den Rest des Tages ab, da sie ein falsches Schema haben.

Eine Anleitung zum Installieren des Legacy-Logging-Agents und zum Aktivieren des strukturierten Loggings finden Sie unter Logging-Agent installieren.

Die Konfigurationsdateien des Legacy-Logging-Agent finden Sie unter /etc/google-fluentd/config.d/. Dort sollten jetzt die Standardparser standardmäßig aktiviert enthalten sein.

Logging-Agent: Format von Apache-Zugriffslogs konfigurieren

Der Legacy-Logging-Agent speichert Apache-Zugriffslogdaten standardmäßig im Feld jsonPayload. Beispiel:

{
  "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"
  },
  ...
}

Alternativ können Sie den Legacy-Logging-Agent so konfigurieren, dass bestimmte Felder in das Feld httpRequest extrahiert werden. Beispiel:

{
  "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"
  },
  ...
}

Die Konfiguration des Felds httpRequest wie im vorherigen Beispiel unterstützt das Tracing: Die Google Cloud Console stellt alle Logs für eine bestimmte HTTP-Anfrage in einer hierarchischen Hierarchie dar.

Fügen Sie zum Konfigurieren dieser Extraktion am Ende von /etc/google-fluentd/config.d/apache.conf Folgendes hinzu:

<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>

Weitere Informationen zum Konfigurieren von Logeinträgen finden Sie unter Logeinträge ändern.

Logging-Agent: Format des nginx-Zugriffslogs konfigurieren

Der Legacy-Logging-Agent speichert nginx-Zugriffslogdaten standardmäßig im Feld jsonPayload. Beispiel:

{
  "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"
  },
  ...
}

Alternativ können Sie den Legacy-Logging-Agent so konfigurieren, dass bestimmte Felder in das Feld httpRequest extrahiert werden. Beispiel:

{
  "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"
  },
  ...
}

Die Konfiguration des Felds httpRequest wie im vorherigen Beispiel unterstützt das Tracing: Die Google Cloud Console stellt alle Logs für eine bestimmte HTTP-Anfrage in einer hierarchischen Hierarchie dar.

Fügen Sie zum Konfigurieren dieser Extraktion am Ende von /etc/google-fluentd/config.d/nginx.conf Folgendes hinzu:

<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>

Weitere Informationen zum Konfigurieren von Logeinträgen finden Sie unter Logeinträge ändern.

Eigenen Parser schreiben

Wenn Ihre Logs von Standardparsern nicht unterstützt werden, können Sie eigene schreiben. Parser bestehen aus einem regulären Ausdruck, mit dem Logdatensätze abgeglichen und Labels auf die Teile angewendet werden.

Die folgenden Codebeispiele zeigen eine Logzeile im Logeintrag, eine Konfiguration mit einem regulären Ausdruck, der das Format der Logzeile angibt, und den gespeicherten Logeintrag:

  • Eine Logzeile im Logdatensatz:

    REPAIR CAR $500
    
  • Eine Konfiguration mit einem regulären Ausdruck, der das Format der Logzeile angibt:

    $ 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>
    
  • Der resultierende Protokolleintrag:

    {
    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"
    }
    

Probleme beheben

Informationen zum Beheben häufiger Probleme bei der Installation oder der Interaktion mit dem Legacy-Logging-Agent finden Sie unter Fehlerbehebung beim Agent.

Nächste Schritte