or run

tessl search
Log in

Version

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
golangpkg:golang/cloud.google.com/go/logging@v1.13.1

docs

architecture.mdclient-logger.mdconstants.mderrors.mdhttp-request.mdindex.mdlogadmin.mdlogger-config.mdpayloads.mdseverity.mdstandard-logger.mdtracing.mdwriting-logs.md
tile.json

tessl/golang-cloud-google-com--go--logging

tessl install tessl/golang-cloud-google-com--go--logging@1.13.0

Cloud Logging client library for Go that enables writing log entries to Google Cloud Logging service with buffered asynchronous and synchronous logging capabilities.

http-request.mddocs/

HTTP Request Metadata

This document describes how to associate log entries with HTTP requests using the HTTPRequest type for correlation and grouping in Cloud Logging.

HTTPRequest Type

type HTTPRequest struct {
    Request                        *http.Request
    RequestSize                    int64
    Status                         int
    ResponseSize                   int64
    Latency                        time.Duration
    LocalIP                        string
    RemoteIP                       string
    CacheHit                       bool
    CacheValidatedWithOriginServer bool
    CacheFillBytes                 int64
    CacheLookup                    bool
}

HTTPRequest contains an http.Request as well as additional information about the request and its response. When included in a log entry, Cloud Logging groups related log entries together and provides request-specific analysis.

Fields:

  • Request *http.Request - The http.Request passed to the handler. This field is required if HTTPRequest is provided.

  • RequestSize int64 - Size of the HTTP request message in bytes, including the request headers and the request body.

  • Status int - Response code indicating the status of the response. Examples: 200, 404.

  • ResponseSize int64 - Size of the HTTP response message sent back to the client, in bytes, including the response headers and the response body.

  • Latency time.Duration - Request processing latency on the server, from the time the request was received until the response was sent.

  • LocalIP string - IP address (IPv4 or IPv6) of the origin server that the request was sent to.

  • RemoteIP string - IP address (IPv4 or IPv6) of the client that issued the HTTP request. Examples: "192.168.1.1", "FE80::0202:B3FF:FE1E:8329".

  • CacheHit bool - Reports whether an entity was served from cache (with or without validation).

  • CacheValidatedWithOriginServer bool - Reports whether the response was validated with the origin server before being served from cache. This field is only meaningful if CacheHit is true.

  • CacheFillBytes int64 - Number of HTTP response bytes inserted into cache. Set only when a cache fill was attempted.

  • CacheLookup bool - Whether or not a cache lookup was attempted.

Basic Usage

import (
    "net/http"
    "time"
    "cloud.google.com/go/logging"
)

func handler(w http.ResponseWriter, r *http.Request) {
    start := time.Now()

    // Process the request
    // ...

    duration := time.Since(start)

    logger.Log(logging.Entry{
        Payload: "request processed",
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request: r,
            Status:  200,
            Latency: duration,
        },
    })
}

Complete Request Metadata

Log comprehensive HTTP request information:

func handlerWithFullMetadata(w http.ResponseWriter, r *http.Request) {
    start := time.Now()

    // Calculate request size
    requestSize := r.ContentLength
    if requestSize < 0 {
        requestSize = 0
    }

    // Process the request
    responseBody := []byte("response data")
    w.WriteHeader(http.StatusOK)
    w.Write(responseBody)

    duration := time.Since(start)

    logger.Log(logging.Entry{
        Payload: "HTTP request completed",
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request:      r,
            RequestSize:  requestSize,
            Status:       http.StatusOK,
            ResponseSize: int64(len(responseBody)),
            Latency:      duration,
            RemoteIP:     r.RemoteAddr,
        },
    })
}

HTTP Middleware

Create middleware to automatically log all HTTP requests:

func loggingMiddleware(logger *logging.Logger) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()

            // Wrap ResponseWriter to capture status code and size
            rw := &responseWriter{
                ResponseWriter: w,
                statusCode:     http.StatusOK,
            }

            // Process request
            next.ServeHTTP(rw, r)

            // Log the request
            logger.Log(logging.Entry{
                Payload: map[string]interface{}{
                    "method": r.Method,
                    "path":   r.URL.Path,
                    "status": rw.statusCode,
                },
                Severity: logging.Info,
                HTTPRequest: &logging.HTTPRequest{
                    Request:      r,
                    Status:       rw.statusCode,
                    ResponseSize: int64(rw.bytesWritten),
                    Latency:      time.Since(start),
                    RemoteIP:     r.RemoteAddr,
                },
            })
        })
    }
}

type responseWriter struct {
    http.ResponseWriter
    statusCode   int
    bytesWritten int
}

func (rw *responseWriter) WriteHeader(code int) {
    rw.statusCode = code
    rw.ResponseWriter.WriteHeader(code)
}

func (rw *responseWriter) Write(b []byte) (int, error) {
    n, err := rw.ResponseWriter.Write(b)
    rw.bytesWritten += n
    return n, err
}

Logging HTTP Errors

func handleAPIRequest(w http.ResponseWriter, r *http.Request) {
    start := time.Now()

    // Process request
    err := processRequest(r)

    if err != nil {
        // Log error with HTTP context
        logger.Log(logging.Entry{
            Payload: map[string]interface{}{
                "error":   err.Error(),
                "message": "request processing failed",
            },
            Severity: logging.Error,
            HTTPRequest: &logging.HTTPRequest{
                Request: r,
                Status:  http.StatusInternalServerError,
                Latency: time.Since(start),
            },
        })

        http.Error(w, "Internal Server Error", http.StatusInternalServerError)
        return
    }

    // Success case
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("success"))

    logger.Log(logging.Entry{
        Payload: "request successful",
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request: r,
            Status:  http.StatusOK,
            Latency: time.Since(start),
        },
    })
}

Cache Metadata

Log cache-related information for CDN or caching layers:

func cacheAwareHandler(w http.ResponseWriter, r *http.Request) {
    start := time.Now()

    // Check cache
    cached, cacheHit := checkCache(r.URL.Path)
    var cacheValidated bool

    if cacheHit {
        // Serve from cache
        w.Write(cached)
    } else {
        // Generate response
        response := generateResponse()
        w.Write(response)

        // Cache the response
        cacheResponse(r.URL.Path, response)
    }

    logger.Log(logging.Entry{
        Payload: "cache-aware request",
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request:                        r,
            Status:                         http.StatusOK,
            Latency:                        time.Since(start),
            CacheHit:                       cacheHit,
            CacheLookup:                    true,
            CacheValidatedWithOriginServer: cacheValidated,
        },
    })
}

IP Address Tracking

Log client and server IP addresses:

func ipTrackingHandler(w http.ResponseWriter, r *http.Request) {
    // Extract client IP (considering proxies)
    clientIP := r.Header.Get("X-Forwarded-For")
    if clientIP == "" {
        clientIP = r.RemoteAddr
    }

    // Get server IP
    serverIP := getServerIP()

    logger.Log(logging.Entry{
        Payload: "request from client",
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request:  r,
            Status:   http.StatusOK,
            RemoteIP: clientIP,
            LocalIP:  serverIP,
        },
    })
}

Grouping Logs by Request

When you include HTTPRequest in log entries, Cloud Logging automatically groups logs from the same request together. This is especially useful for distributed systems:

func complexHandler(w http.ResponseWriter, r *http.Request) {
    // Log request start
    logger.Log(logging.Entry{
        Payload:  "processing request",
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request: r,
        },
    })

    // Log database query
    logger.Log(logging.Entry{
        Payload:  "querying database",
        Severity: logging.Debug,
        HTTPRequest: &logging.HTTPRequest{
            Request: r,
        },
    })

    // Log external API call
    logger.Log(logging.Entry{
        Payload:  "calling external API",
        Severity: logging.Debug,
        HTTPRequest: &logging.HTTPRequest{
            Request: r,
        },
    })

    // Log completion
    logger.Log(logging.Entry{
        Payload:  "request completed",
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request: r,
            Status:  http.StatusOK,
        },
    })
}

All these log entries will be grouped together in Cloud Logging because they reference the same HTTP request.

Complete Example

package main

import (
    "context"
    "log"
    "net/http"
    "time"

    "cloud.google.com/go/logging"
)

var logger *logging.Logger

func main() {
    ctx := context.Background()

    client, err := logging.NewClient(ctx, "my-project")
    if err != nil {
        log.Fatalf("failed to create client: %v", err)
    }
    defer client.Close()

    logger = client.Logger("http-log")

    http.HandleFunc("/api/users", userHandler)
    http.ListenAndServe(":8080", nil)
}

func userHandler(w http.ResponseWriter, r *http.Request) {
    start := time.Now()

    // Log incoming request
    logger.Log(logging.Entry{
        Payload: map[string]interface{}{
            "event":  "request_received",
            "method": r.Method,
            "path":   r.URL.Path,
        },
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request: r,
        },
    })

    // Process request
    var statusCode int
    var responseBytes []byte

    if r.Method == "GET" {
        statusCode = http.StatusOK
        responseBytes = []byte(`{"users": []}`)
    } else {
        statusCode = http.StatusMethodNotAllowed
        responseBytes = []byte(`{"error": "method not allowed"}`)
    }

    // Send response
    w.WriteHeader(statusCode)
    w.Write(responseBytes)

    duration := time.Since(start)

    // Log request completion
    severity := logging.Info
    if statusCode >= 400 {
        severity = logging.Warning
    }
    if statusCode >= 500 {
        severity = logging.Error
    }

    logger.Log(logging.Entry{
        Payload: map[string]interface{}{
            "event":    "request_completed",
            "method":   r.Method,
            "path":     r.URL.Path,
            "status":   statusCode,
            "duration": duration.Milliseconds(),
        },
        Severity: severity,
        HTTPRequest: &logging.HTTPRequest{
            Request:      r,
            Status:       statusCode,
            ResponseSize: int64(len(responseBytes)),
            Latency:      duration,
            RemoteIP:     r.RemoteAddr,
        },
    })
}

Benefits of HTTPRequest Metadata

  1. Automatic Grouping: Cloud Logging groups log entries from the same request together
  2. Request Analysis: View request duration, status codes, and response sizes in Cloud Logging console
  3. Correlation: Correlate logs across distributed systems using trace context (see Tracing)
  4. Filtering: Filter logs by HTTP method, status code, or request path
  5. Performance Monitoring: Analyze request latencies and identify slow requests
  6. Error Investigation: Quickly find all logs related to failed requests