W tym artykule pokażę, jak skonfigurować logowanie w aplikacji napisanej przy użyciu biblioteki Ktor, uruchamianej na Google Cloud Run, aby logi były widoczne w konsoli Cloud Logging. Pokażę również, jak korzystać ze strukturyzowanych logów i jak dodawać trace ID, aby łatwiej analizować wywołania i problemy w środowisku produkcyjnym.
Dlaczego logowanie w chmurze jest ważne?
Cloud Run to środowisko zarządzane, w związku z czym nie mamy dostępu do maszyn, na których działa aplikacja. Dlatego jedynym źródłem diagnostyki są:
-
logi aplikacyjne
-
metryki
-
śledzenie (trace)
-
i ewentualne alerty
Poprawna konfiguracja logowania to fundament skutecznego monitoringu.
Konfiguracja SLF4J
Zacznijmy od najprostszego podejścia, czyli logowania na konsolę. Pozwala to środowisku Cloud Run automatycznie przechwycić logi
W tym celu warto sięgnąć po logback, który w połączeniu z logstash-logback-encoder pozwala logować zdarzenia w formacie JSON. Dzięki temu możemy w pełni wykorzystać możliwości Google Cloud Logging: filtrowanie logów, korelacja z trace ID, analiza w czasie rzeczywistym.
Choć slf4j-simple jest wygodny dla szybkiego debugowania lokalnie, w środowiskach produkcyjnych nie daje wystarczających możliwości konfiguracji.
Aby uruchomić logowanie przy pomocy Slf4J i Logback w aplikacji należy dodać odpowiednie zależności:
dependencies {
implementation("ch.qos.logback:logback-classic:1.4.14")
implementation("org.slf4j:slf4j-api:2.0.13")
}
oraz stworzyć plik plik src/main/resources/logback.xml:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{yyyy-MM-dd'T'HH:mm:ss.SSSXXX} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
Śledzenie requestów w Ktor na Cloud Run z wykorzystaniem traceparent oraz CallLogging
Śledzenie żądań (request tracing) to kluczowy element monitorowania aplikacji produkcyjnych. W środowisku takim jak Google Cloud Run, każde żądanie może posiadać trace ID, który umożliwia śledzenie jego przetwarzania przez różne komponenty systemu (np. Cloud Load Balancer → Cloud Run → Pub/Sub → Cloud Function).
Od 2023 roku Google Cloud zaleca używanie nagłówka traceparent (zgodnego z W3C Trace Context
) zamiast starszego X-Cloud-Trace-Context.
W tym rozdziale pokażę jak poprawnie obsłużyć traceparent w aplikacji Ktor oraz jak uwzględnić ten identyfikator w strukturze logów zgodnych z Cloud Logging.
Po co traceparent?
Google Cloud Platform automatycznie dodaje do każdego żądania nagłówek:
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
Gdzie: - 00 - to stała wartość określająca wersję protokołu - 4bf92f3577b34da6a3ce929d0e0e4736 – to trace ID (unikalny dla całego żądania), - 00f067aa0ba902b7 – to span ID (konkretna sekcja śledzenia), - 01 – to trace flag (np. czy logować).
Cloud Logging oczekuje, że Twoje logi będą zawierać pole:
logging.googleapis.com/trace: projects/PROJECT_ID/traces/TRACE_ID
Włączenie obsługi traceparent przy pomocy CallLoging
Poniższy kod instaluje moduł CallLoging, oraz wykorzystuje go do ustawienia w kontekscie logowania wymaganego przez GCP pola.
fun Application.configureLogging(projectId: String) {
install(CallLogging) {
mdc("logging.googleapis.com/trace") { call ->
val traceParent = call.request.headers["traceparent"]
val traceId = traceParent?.split("-")?.getOrNull(1)
traceId?.let { "projects/$projectId/traces/$it" }
}
}
}
Aby wykorzystać tak skonfigurowane MCD, konieczne jest jeszcze odpowiednie wysterowanie biblioteki Logback. W tym celu wykorzystamy Logstash Logback Encoder, który automatycznie tworzy wpisy w formacie JSON:
<configuration>
<include resource="net/logstash/logback/logback-include.xml"/>
<appender name="JSON_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder">
<providers>
<timestamp/>
<logLevel/>
<threadName/>
<loggerName/>
<message/>
<mdc />
<stackTrace/>
</providers>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="JSON_CONSOLE"/>
</root>
</configuration>
Jak to wygląda w Cloud Logging?
Po wdrożeniu aplikacji na Cloud Run i wykonaniu żądania, w Cloud Logging pojawi się wpis podobny do poniższego:
{
"@timestamp": "2025-09-14T17:02:35.997055+02:00",
"level": "INFO",
"thread_name": "eventLoopGroupProxy-4-1",
"logger_name": "io.ktor.server.Application",
"message": "\u001B[32m200 OK\u001B[m: \u001B[36mGET\u001B[m - / in 383ms",
"logging.googleapis.com/trace": "projects/unknown/traces/abcdef0123456789abcdef0123456789",
"logging.googleapis.com/trace_sampled": "true",
"logging.googleapis.com/spanId": "0123456789abcdef"
}
Testowanie lokalne
Lokalnie możesz dodać nagłówek traceparent w Postmanie lub curl:
curl -H "traceparent: 00-abcdef0123456789abcdef0123456789-0123456789abcdef-01" http://localhost:8080/
Dobre praktyki
-
loguj zawsze na stdout, nie twórz lokalnych plików logów
-
loguj w formacie JSON. Daje to filtrowalne, strukturyzowane dane w GCP
-
przekazuj
logging.googleapis.com/trace– ułatwia to analizę żądań między usługami -
używaj INFO, WARN, ERROR zgodnie z poziomem ważności
-
pamiętaj o anonimizacji danych wrażliwych
Podsumowanie
Dzięki poprawnej konfiguracji logi trafiają bezpośrednio do Cloud Logging i masz natychmiastowy wgląd w działanie aplikacji. Ponadto możesz analizować i debugować problemy szybciej dzięki wspieraniu trace’owanie i strukturyzację danych diagnostycznych.
W następnym artykule pokażę, jak skonfigurować metryki, alerty i obserwowalność z użyciem Cloud Monitoring.
Kompletny kod dla artykułów z serii znajduje się tutaj: tutaj.
Inne artykuły z serii
-
Wprowadzenie
-
Pierwsze wdrożenie