Logowanie w Ktor i podgląd logów w GCP Cloud Logging

· 705 słów · do przeczytania, w minut 4

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.