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.

standard-logger.mddocs/

Standard Logger Integration

This document describes how to integrate Cloud Logging with Go's standard library log.Logger for compatibility with existing logging code.

StandardLogger Method

func (l *Logger) StandardLogger(s Severity) *log.Logger

Returns a *log.Logger for the provided severity level. This method is cheap because a single log.Logger is pre-allocated for each severity level in each Logger. Callers may mutate the returned log.Logger (for example by calling SetFlags or SetPrefix).

Parameters:

  • s - The severity level for all log entries written by the returned logger

Returns:

  • *log.Logger - A standard library logger that writes to Cloud Logging

Example:

import (
    "cloud.google.com/go/logging"
    "log"
)

logger := client.Logger("my-log")

// Get standard logger for Info severity
stdLogger := logger.StandardLogger(logging.Info)

// Use like any standard logger
stdLogger.Println("This is an info message")
stdLogger.Printf("User %s logged in", userID)

// Get standard loggers for different severities
debugLogger := logger.StandardLogger(logging.Debug)
errorLogger := logger.StandardLogger(logging.Error)

debugLogger.Println("Debug information")
errorLogger.Println("An error occurred")

StandardLoggerFromTemplate Method

func (l *Logger) StandardLoggerFromTemplate(template *Entry) *log.Logger

Returns a Go Standard Logging API *log.Logger that emits logs using the provided template Entry struct. The returned logger emits logs using logging.(*Logger).Log() with an entry constructed from the provided template Entry struct.

The caller is responsible for ensuring that the template Entry struct does not change during the lifetime of the returned *log.Logger.

Prefer (*Logger).StandardLogger() which is more efficient if the template only sets Severity.

Parameters:

  • template - An Entry struct to use as a template for all log entries

Returns:

  • *log.Logger - A standard library logger that writes to Cloud Logging with the template

Example:

import (
    "cloud.google.com/go/logging"
    "log"
)

logger := client.Logger("my-log")

// Create template with labels and metadata
template := &logging.Entry{
    Severity: logging.Info,
    Labels: map[string]string{
        "service":     "api-gateway",
        "environment": "production",
    },
}

// Create standard logger from template
stdLogger := logger.StandardLoggerFromTemplate(template)

// All logs will include the template's severity and labels
stdLogger.Println("Request processed")
stdLogger.Printf("User %s authenticated", userID)

Basic Usage

Replace existing standard loggers with Cloud Logging:

package main

import (
    "context"
    "log"

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

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("app-log")

    // Replace default logger
    log.SetOutput(logger.StandardLogger(logging.Info).Writer())
    log.SetFlags(0) // Cloud Logging adds its own metadata

    // Now all log.Print calls go to Cloud Logging
    log.Println("Application started")
    log.Printf("Listening on port %d", 8080)
}

Multiple Severity Levels

Use different standard loggers for different severity levels:

var (
    debugLog   *log.Logger
    infoLog    *log.Logger
    warningLog *log.Logger
    errorLog   *log.Logger
)

func initLoggers(logger *logging.Logger) {
    debugLog = logger.StandardLogger(logging.Debug)
    infoLog = logger.StandardLogger(logging.Info)
    warningLog = logger.StandardLogger(logging.Warning)
    errorLog = logger.StandardLogger(logging.Error)
}

func main() {
    ctx := context.Background()
    client, _ := logging.NewClient(ctx, "my-project")
    defer client.Close()

    logger := client.Logger("app-log")
    initLoggers(logger)

    debugLog.Println("Debug information")
    infoLog.Println("Application started")
    warningLog.Println("Configuration incomplete, using defaults")
    errorLog.Println("Failed to connect to database")
}

Custom Formatting

Customize the standard logger with prefixes and flags:

logger := client.Logger("my-log")
stdLogger := logger.StandardLogger(logging.Info)

// Add prefix
stdLogger.SetPrefix("[APP] ")

// Set flags (note: Cloud Logging adds its own timestamps)
stdLogger.SetFlags(log.Lshortfile) // Include file:line

stdLogger.Println("This message has prefix and file location")
// Output in Cloud Logging: [APP] main.go:123: This message has prefix and file location

Integration with Existing Code

Migrate existing code that uses standard library logging:

// Before: Using standard library
import "log"

func processRequest(data string) {
    log.Printf("Processing: %s", data)
}

// After: Using Cloud Logging with minimal changes
import (
    "log"
    "cloud.google.com/go/logging"
)

var stdLogger *log.Logger

func init() {
    ctx := context.Background()
    client, _ := logging.NewClient(ctx, "my-project")
    logger := client.Logger("app-log")
    stdLogger = logger.StandardLogger(logging.Info)
}

func processRequest(data string) {
    stdLogger.Printf("Processing: %s", data)
}

Template with HTTP Request Context

Use templates to include HTTP request metadata:

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

func handler(w http.ResponseWriter, r *http.Request) {
    // Create template with HTTP request
    template := &logging.Entry{
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request: r,
        },
        Labels: map[string]string{
            "handler": "user-api",
        },
    }

    stdLogger := logger.StandardLoggerFromTemplate(template)

    // All logs include HTTP request context
    stdLogger.Println("Processing user request")
    stdLogger.Printf("User ID: %s", getUserID(r))

    // These logs will be grouped with the HTTP request in Cloud Logging
}

Template with Operation Context

Include operation tracking in standard logger:

import (
    "cloud.google.com/go/logging"
    logpb "cloud.google.com/go/logging/apiv2/loggingpb"
)

func longRunningOperation(operationID string) {
    template := &logging.Entry{
        Severity: logging.Info,
        Operation: &logpb.LogEntryOperation{
            Id:       operationID,
            Producer: "batch-processor",
        },
        Labels: map[string]string{
            "operation_type": "batch",
        },
    }

    opLogger := logger.StandardLoggerFromTemplate(template)

    opLogger.Println("Operation started")
    opLogger.Println("Processing batch 1/10")
    opLogger.Println("Processing batch 2/10")
    // ...
    opLogger.Println("Operation completed")

    // All logs are associated with the same operation
}

Global Logger Replacement

Replace the global default logger:

package main

import (
    "context"
    "log"

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

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("app-log")

    // Replace global logger
    stdLogger := logger.StandardLogger(logging.Info)
    log.SetOutput(stdLogger.Writer())
    log.SetFlags(0)

    // Now all existing code using log.Print* works with Cloud Logging
    log.Println("Global logger now uses Cloud Logging")

    // Even third-party libraries using log.Print* will log to Cloud Logging
    runThirdPartyCode()
}

Per-Package Loggers

Create separate standard loggers for different packages:

package database

import (
    "log"
    "cloud.google.com/go/logging"
)

var dbLogger *log.Logger

func InitLogger(logger *logging.Logger) {
    template := &logging.Entry{
        Severity: logging.Debug,
        Labels: map[string]string{
            "component": "database",
        },
    }
    dbLogger = logger.StandardLoggerFromTemplate(template)
}

func Query(sql string) {
    dbLogger.Printf("Executing query: %s", sql)
}
package api

import (
    "log"
    "cloud.google.com/go/logging"
)

var apiLogger *log.Logger

func InitLogger(logger *logging.Logger) {
    template := &logging.Entry{
        Severity: logging.Info,
        Labels: map[string]string{
            "component": "api",
        },
    }
    apiLogger = logger.StandardLoggerFromTemplate(template)
}

func HandleRequest() {
    apiLogger.Println("Handling API request")
}

Error Handling

Standard loggers don't return errors, but errors are reported via Client.OnError:

ctx := context.Background()
client, _ := logging.NewClient(ctx, "my-project")
defer client.Close()

// Set error handler
client.OnError = func(err error) {
    // Handle logging errors
    fmt.Fprintf(os.Stderr, "Logging error: %v\n", err)
}

logger := client.Logger("my-log")
stdLogger := logger.StandardLogger(logging.Info)

// Errors during logging will be reported to OnError
stdLogger.Println("This is logged asynchronously")

Complete Example

package main

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

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

var (
    infoLogger  *log.Logger
    errorLogger *log.Logger
)

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

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

    // Set error handler
    client.OnError = func(err error) {
        log.Printf("Logging error: %v", err)
    }

    // Create logger
    logger := client.Logger("app-log", logging.CommonLabels(map[string]string{
        "service": "web-server",
    }))

    // Initialize standard loggers
    infoLogger = logger.StandardLogger(logging.Info)
    errorLogger = logger.StandardLogger(logging.Error)

    // Replace global logger
    log.SetOutput(infoLogger.Writer())
    log.SetFlags(0)

    // Log application startup
    infoLogger.Println("Application starting")
    log.Printf("Listening on port 8080")

    // Start server
    http.HandleFunc("/", requestHandler)
    if err := http.ListenAndServe(":8080", nil); err != nil {
        errorLogger.Printf("Server failed: %v", err)
        os.Exit(1)
    }
}

func requestHandler(w http.ResponseWriter, r *http.Request) {
    // Create request-specific logger
    template := &logging.Entry{
        Severity: logging.Info,
        HTTPRequest: &logging.HTTPRequest{
            Request: r,
        },
    }

    reqLogger := logger.StandardLoggerFromTemplate(template)

    reqLogger.Printf("Received %s request for %s", r.Method, r.URL.Path)

    // Process request
    if r.URL.Path == "/error" {
        errorLogger.Println("Error endpoint accessed")
        http.Error(w, "Error", http.StatusInternalServerError)
        return
    }

    reqLogger.Println("Request processed successfully")
    w.WriteHeader(http.StatusOK)
    w.Write([]byte("OK"))
}

Performance Considerations

  • StandardLogger() is cheap because loggers are pre-allocated
  • Standard loggers write asynchronously via the underlying Cloud Logging logger
  • For high-performance scenarios, consider using Logger.Log() directly for better control
  • Template-based loggers create the template Entry on each write, which is slightly slower

Related Documentation

  • Writing Log Entries - Direct logging with Logger.Log()
  • Logger Configuration - Configure logging behavior
  • HTTP Request Metadata - Include HTTP context in logs