[GO] Was ich getan habe, um Anwendungsprotokolle in der GAE Flexible Environment auszugeben.

Protokollausgabe in der flexiblen Umgebung von GoogleAppengine

Jeder, wenn Sie eine Anwendung erstellen, spucken Sie die Protokolle in den Speicher auf dem Anwendungsserver aus? ??

Wenn Sie in GAE / go (Standardumgebung) "google.golang.org / appengine / log" verwenden, wird es an den Protokoll-Viewer ausgegeben. Sie können das Protokoll einfach filtern usw. "Was für ein Wunder!" Ich glaube ich war beeindruckt.

スクリーンショット_2016-12-06_17_44_49.png

GAE / FE gab jedoch keine Ausgabe an den Protokoll-Viewer aus, ohne etwas zu tun.

Ich hatte große Probleme und konnte wie erwartet ausgeben, daher werde ich es detailliert schreiben, da es eines Tages für jemanden nützlich sein kann, einschließlich verschiedener Untersuchungen.

Protokollausgabestrategie (erste Generation)

Die erste Protokollausgabemethode, an die ich dachte, war, die StackDriver-Protokollierungs-API (v2) selbst zu aktivieren. → hier

Bei Verwendung dieser Methode muss das Ausgabeziel (API-Verbindungsziel) sortiert werden, wenn in der lokalen Entwicklungsumgebung, in der Staging-Umgebung, in der Produktionsumgebung und bei einer Anforderung getroffen wird Da es nicht sinnvoll ist, die API mehrmals aufzurufen, muss ein Mechanismus erstellt werden, um Schreibvorgänge im Anforderungsbereich zu puffern und die Protokollierungs-API auszuführen.

In einer solchen Situation wird fluentd in der FE-Umgebung ausgeführt, und ich habe die Information erhalten, dass die im entsprechenden Format ausgespuckte Datei im entsprechenden Format an den Protokollbetrachter ausgegeben wird und die Protokollausgabestrategie sofort an die zweite Generation geht.

Protokollausgabestrategie (zweite Generation)

In der FE-Umgebung wird ein Agent installiert und ein Mechanismus zur Ausgabe von Protokollen vorbereitet.

`Um Ihre flexible App Engine-Umgebungsanwendung mit Stackdriver Error Reporting zu verbinden, senden Sie strukturierte Daten an eine benutzerdefinierte Protokolldatei. ``

`Der Stackdriver-Protokollierungsagent wird mit den Standardeinstellungen der App Engine Flexible Environment-App installiert und konfiguriert. ``

https://cloud.google.com/error-reporting/docs/setup/app-engine-flexible-environment

Ich verstehe, ich bin dafür dankbar. Laut den Informationen können Sie durch Ausgabe in eine feste Datei in einem festen Format diese gut sammeln. Wann.

Was ist die feste Datei und das feste Format?

Ich verstehe, dass es einen Mechanismus für die Ausgabe gibt, aber ich kenne das Ausgabeziel und die Form des auszugebenden JSON nicht ...

Ich habe auf Dokumente wie Verwenden der Cloud-Protokollierung in App Engine-Apps verwiesen, aber es funktioniert nicht subtil.

Ist es nicht schneller, das Dokument von diesem Punkt an aufzugeben und den Quellcode und die Umgebung kontinuierlich zu untersuchen? Ich fühlte das, also wechselte ich zu dieser Methode.

Betrachten Sie zunächst die Umgebung, während Sie sich das Repository mit Einstellungen rund um den Container der FE-Umgebung mit dem Namen Managed VM Sidecar Containers ansehen.

Instanzen der FE-Umgebung können ssh verbunden werden.

Schreiben Sie Code → Bereitstellen → Warten Sie bis zum Tod, bis Sie feststellen, dass Sie eine Verbindung zu ssh herstellen können. Es war eine Buße, aber wenn Sie sich verbinden können, diese. Ich werde verschiedene Dinge untersuchen.

Klicken Sie auf "Instanz" von appengine und dann auf "SSH" der Instanz, um das Terminal im Browser zu starten. スクリーンショット_2016-12-06_18_23_01.png

Das vom Terminal verbundene Ziel ist eine Instanz der FE-Umgebung. (Vielleicht ist es eine GCE-Instanz?) Lassen Sie uns den Container überprüfen, der mit dem folgenden Befehl ausgeführt wird.

$ sudo docker ps
CONTAINER ID        IMAGE                                                                                                                         COMMAND                  CREATED             STATUS              PORTS                                        NAMES
61096f77d1a5        gcr.io/google_appengine/nginx-proxy                                                                                           "/var/lib/nginx/bin/s"   About an hour ago   Up About an hour    8080/tcp, 8090/tcp, 0.0.0.0:8443->8443/tcp   thirsty_brattain
3e176f20673a        us.gcr.io/fe-stud/appengine/default.20161206t152342@sha256:330d6b553033c80ad0313fe3c2fd713bdaec873197d00193b6f8a32beda0ca73   "/docker-entrypoint.b"   About an hour ago   Up About an hour    8080/tcp                                     gaeapp
73675d907c83        gcr.io/google_appengine/api-proxy                                                                                             "/proxy"                 About an hour ago   Up About an hour                                                 api
5430f456d28c        gcr.io/google_appengine/fluentd-logger                                                                                        "/opt/google-fluentd/"   About an hour ago   Up About an hour                                                 stupefied_heisenberg

In der FE-Umgebungsinstanz werden vier Container auf Docker ausgeführt, und es scheint, dass der fließende Container das Protokoll aufnimmt und sendet, wenn das Protokoll aus der Gaeapp (Anwendung) in das Verzeichnis der gemeinsam genutzten Hostinstanz gespuckt wird. スクリーンショット 2016-12-06 18.12.06.png

Da es fließend ist, wird die zu sammelnde Protokolldatei in [Datei in Github] definiert (https://github.com/GoogleCloudPlatform/appengine-sidecars-docker/blob/master/fluentd_logger/managed_vms.conf).

/fluentd_logger/managed_vms.conf

Es ist wie folgt.

Dateimuster
/var/log/app_engine/app/app*.log
/var/log/app_engine/app/app*.json
/var/log/app_engine/app/request*.log
/var/log/app_engine/app/STDOUT*.log
/var/log/app_engine/app/STDERR*.log
/var/log/app_engine/app/custom_logs/*.log
/var/log/app_engine/app/custom_logs/*.json
/var/log/app_engine/monitoring/*.log
/var/log/syslog

Ich frage mich, ob dies das Standardziel ist. Beachten Sie, dass dies der Pfad innerhalb des fließenden Behälters ist! (Ich war ein wenig süchtig nach dem Glauben, dass der gleiche Weg im Gaeapp-Container sein würde ...)

Hier ist, wie ich süchtig wurde. Korrespondenztabelle für Verzeichnispfade

Der Pfad, auf dem der Gaeapp-Container montiert ist Protokollverzeichnis in der Hostinstanz Der Pfad, den der fließende Container bereitstellt
/var/log/app_engine /var/log/app_engine/app /var/log/app_engine/app

Hast du bemerkt? Ja, der Pfad des Protokollverzeichnisses der Hostinstanz und des Containers von fluentd sind identisch, aber aus irgendeinem Grund ist der Pfad des Protokollverzeichnisses von gaeapp unterschiedlich. .. ..

Selbst wenn ich mir die Fluentd-Einstellungsdatei ansehe und die Protokolldatei in gaeapp für dieses Verzeichnis ausgebe, nimmt Fluentd sie nicht auf ... (Tränen).

Ich denke, es ist eine gute Idee, in den fließenden Behälter zu gehen und es zu versuchen, während Sie das Protokoll verfolgen.

So geben Sie den fließenden Container auf der Hostinstanz ein

$ sudo docker exec -it stupefied_heisenberg bash

Betreten Sie den Container mit

# tail -f /var/log/google-fluentd/google-fluentd.log

Sie können es bei sehen. Übrigens, wenn das Protokoll von fluentd korrekt aufgenommen wurde

2016-12-06 07:47:25 +0000 [info]: following tail of /var/log/app_engine/app/app.json
2016-12-06 07:54:25 +0000 [info]: following tail of /var/log/app_engine/app/app.log.json

Ein solches Protokoll wird ausgegeben. (Beachten Sie, dass es nur ausgegeben wird, wenn die Datei zum ersten Mal gefunden wird.)

Welches JSON-Format ist für die Ausgabe erforderlich? ??

Wie wird ein Protokoll, das nicht im JSON-Format vorliegt, vom Protokoll-Viewer ausgegeben?

Textprotokolle werden als Text ausgegeben, wenn sie in eine Datei mit der Erweiterung "* .log" ausgegeben werden. Der Unterschied zum Protokoll im JSON-Format besteht darin, dass Informationen wie die Protokollebene nicht hinzugefügt werden können.

Beispiel für die Ausgabe von app.log スクリーンショット 2016-12-06 18.46.25.png Entschuldigung für das längliche Bild. .. Bei der Ausgabe als Text (der Inhalt ist im Beispiel im JSON-Format) wird er ohne Protokollebene ausgegeben (Symbol links).

Ich möchte immer noch die Protokollstufe bei der Ausgabe aus der Anwendung. Daher wird das für die Ausgabe erforderliche JSON-Format unten angezeigt.

So geben Sie ein Protokoll im JSON-Format aus und geben es sauber an den Protokoll-Viewer aus. (Finales Kapitel?)

Verwenden Sie JsonFormatter.java und LogContext.java in appengine-java-vm-runtime, um den JSON zu formatieren. ..

Selbst wenn es in anderen Sprachen verwendet wird, führt die Formatierungsmethode in JsonFormatter.java keine so schwierige Verarbeitung durch, daher denke ich, dass Sie es implementieren können, indem Sie darauf verweisen.

Die Schlussfolgerung ist also das Beispiel im JSON-Format, das wie folgt lautet.

{
  "timestamp":{"seconds":1481005920,"nanos":927000000},
  "severity":"ERROR",
  "thread":"qtp1347137144-13",
  "message":"TestLogger: === TEST LOG ==="
}

Übrigens, wenn Sie den vorherigen "JsonFormatter" verwenden, verwenden Sie "java.util.logging.LogRecord", aber als Einschränkung müssen Sie den Loggernamen mit "LogRecord # setLoggerName" eingeben. Es verursacht keinen Fehler, auch wenn ich ihn nicht eingebe, aber die JSON-Nachricht sieht aus wie "null: === TEST LOG ===" und ist nicht cool.

Grober Beispielcode

Level level = Level.SEVERE; //Protokollstufe, entspricht Fehler
LogRecord record = new LogRecord(level, "=== TEST LOG ===");
record.setLoggerName("TestLogger");
JsonFormatter formatter = new JsonFormatter();
String logString = formatter.format(record); //Sie können diesen String als Zeile in der JSON-Datei ausgeben.

Wenn Sie sich bisher vorbereiten können, können Sie JSON in eine Datei ausspucken und sauber an den Protokoll-Viewer ausgeben. スクリーンショット_2016-12-06_18_57_25.png Das Beispiel wird auf der Fehlerebene ausgegeben, daher gibt es ein Symbol, das nicht nur eine Sache zu sein scheint [! !! ]]

Ausgabemethode in Java (Anhang)

Bei Verwendung mit Scala (Java) möchte ich mit slf4j / logback usw. ausgeben, konnte aber mit der folgenden Methode ausgeben.

Fügen Sie "appengine-java-logging" und "appengine-manage-runtime" zur "pom.xml" des Projekts hinzu

pom.xml


<!-- https://mvnrepository.com/artifact/com.google.appengine/appengine-java-logging -->
<dependency>
    <groupId>com.google.appengine</groupId>
    <artifactId>appengine-java-logging</artifactId>
    <version>1.9.31</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.appengine/appengine-managed-runtime -->
<dependency>
    <groupId>com.google.appengine</groupId>
    <artifactId>appengine-managed-runtime</artifactId>
    <version>1.9.31</version>
</dependency>

Rufen Sie irgendwo in Ihrer Anwendung VmRuntimeFileLogHandler # init auf.

Dies gibt intern die Einstellungen für die Protokollausgabe an.

VmRuntimeFileLogHandler.java


// ~~ snip ~~
    private static String fileLogPattern() {
        String pattern = System.getenv("APP_ENGINE_LOG_CONFIG_PATTERN");
        if(pattern != null) {
            return pattern;
        } else {
            String directory = System.getProperty("com.google.apphosting.logs", "/var/log/app_engine");
            pattern = System.getProperty("com.google.apphosting.vmruntime.VmRuntimeFileLogHandler.pattern");
            return pattern != null?(pattern.startsWith("/")?pattern:directory + "/" + pattern):directory + "/" + "app.%g.log.json";
        }
    }
// ~~ snip ~~

Sie können den angegebenen Inhalt in "logback.xml" usw. veröffentlichen, indem Sie auf diese Klasse verweisen. In diesem Fall müssen Sie nicht VmRuntimeFileLogHandler # init aufrufen.

Generieren Sie einen Logger und geben Sie ein Log aus

LogSample.java


Logger logger = Logger.getLogger("com");  //Logger-Generierung

logger.warning("= WARNING TEST ="); //Protokollausgabe

Stellen Sie nach Bedarf logging.properties ein

.level=ALL

com.level=SEVERE

Vielen Dank

Wir möchten @soundTricker dafür danken, dass er uns verschiedene Informationen und Beratung zur Protokollausgabe in der FE-Umgebung zur Verfügung gestellt hat.

Recommended Posts

Was ich getan habe, um Anwendungsprotokolle in der GAE Flexible Environment auszugeben.
Was ich getan habe, um eine SSH-Verbindung zur VPS Ubuntu-Umgebung herzustellen
Was ich getan habe, um Python-Speicher zu speichern
[Python] Was ich getan habe, um Unit Test zu machen
Was ich beim Update von Python 2.6 auf 2.7 gemacht habe
Wovon ich beim Erstellen von Webanwendungen in einer Windows-Umgebung abhängig war
Ich möchte Android-Apps auf Android entwickeln (Debug)
Was ich getan habe, um die String-Suchaufgabe zu beschleunigen
Was ich getan habe, um die Python2 EOL mit Zuversicht zu begrüßen
Ich habe versucht, eine Serverumgebung zu erstellen, die unter Windows 10 ausgeführt wird
Ich habe versucht, eine Umgebung von MkDocs unter Amazon Linux zu erstellen
Beachten Sie, was Sie getan haben, um Flycheck mit Python zu verwenden
Ich weiß nicht, wie ich Abfrageparameter in GAE / P erhalten soll
Ich habe versucht zusammenzufassen, was mit Qiita mit Word Cloud ausgegeben wurde
Was ich getan habe, als ich Python schneller machen wollte - Numba Edition -
H29.2.27 ~ 3.5 Zusammenfassung meiner Arbeit
Was ich getan habe, um die Luftfeuchtigkeit und Temperatur des Archivs zu verfolgen
[Bei Coder] Was ich getan habe, um den grünen Rang in Python zu erreichen