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.

payloads.mddocs/

Payload Types and Formatting

This document describes the different payload types supported by Cloud Logging entries and how to use them.

Payload Field

type Entry struct {
    // ...
    Payload interface{}
    // ...
}

The Payload field of an Entry can be:

  • A string
  • Any value that marshals via encoding/json to a JSON object (not any other type of JSON value)
  • json.RawMessage for raw JSON bytes
  • anypb.Any for protobuf messages

String Payloads

The simplest payload type is a string:

logger.Log(logging.Entry{
    Payload: "something happened",
})

logger.Log(logging.Entry{
    Payload:  "user authentication successful",
    Severity: logging.Info,
})

Struct Payloads

You can log any Go struct that can be marshaled to JSON:

type UserEvent struct {
    UserID    string
    Action    string
    Timestamp time.Time
    Success   bool
}

event := UserEvent{
    UserID:    "user-12345",
    Action:    "login",
    Timestamp: time.Now(),
    Success:   true,
}

logger.Log(logging.Entry{
    Payload:  event,
    Severity: logging.Info,
})

The struct will be marshaled to a JSON object in Cloud Logging:

{
  "UserID": "user-12345",
  "Action": "login",
  "Timestamp": "2024-01-15T10:30:00Z",
  "Success": true
}

Using JSON Tags

Use JSON tags to control field names in the logged output:

type PaymentEvent struct {
    UserID      string  `json:"user_id"`
    Amount      float64 `json:"amount"`
    Currency    string  `json:"currency"`
    Status      string  `json:"status"`
    ProcessedAt time.Time `json:"processed_at"`
}

payment := PaymentEvent{
    UserID:      "user-67890",
    Amount:      99.99,
    Currency:    "USD",
    Status:      "completed",
    ProcessedAt: time.Now(),
}

logger.Log(logging.Entry{
    Payload:  payment,
    Severity: logging.Info,
})

Omitting Empty Fields

Use omitempty to exclude zero-value fields:

type ErrorEvent struct {
    ErrorCode    string `json:"error_code"`
    ErrorMessage string `json:"error_message"`
    StackTrace   string `json:"stack_trace,omitempty"`
    UserID       string `json:"user_id,omitempty"`
}

// StackTrace and UserID will be omitted if empty
event := ErrorEvent{
    ErrorCode:    "AUTH_FAILED",
    ErrorMessage: "Invalid credentials",
}

logger.Log(logging.Entry{
    Payload:  event,
    Severity: logging.Error,
})

Map Payloads

You can use map[string]interface{} for dynamic payloads:

payload := map[string]interface{}{
    "event_type": "purchase",
    "user_id":    "user-12345",
    "items": []map[string]interface{}{
        {
            "product_id": "prod-001",
            "quantity":   2,
            "price":      29.99,
        },
        {
            "product_id": "prod-002",
            "quantity":   1,
            "price":      49.99,
        },
    },
    "total":    109.97,
    "currency": "USD",
}

logger.Log(logging.Entry{
    Payload:  payload,
    Severity: logging.Info,
})

Raw JSON Payloads

If you already have JSON as a []byte, wrap it in json.RawMessage to avoid double-encoding:

import "encoding/json"

// JSON data from an external source
jsonData := []byte(`{
    "Name": "Bob",
    "Count": 3,
    "Active": true
}`)

logger.Log(logging.Entry{
    Payload:  json.RawMessage(jsonData),
    Severity: logging.Info,
})

This is useful when:

  • Receiving JSON from HTTP requests
  • Reading JSON from files
  • Forwarding JSON from other systems
  • Avoiding marshaling overhead

Protobuf Payloads

For protobuf messages, marshal them to anypb.Any:

import (
    "google.golang.org/protobuf/proto"
    "google.golang.org/protobuf/types/known/anypb"
)

// Assuming you have a proto.Message
func logProtoMessage(logger *logging.Logger, msg proto.Message) error {
    var payload anypb.Any
    err := anypb.MarshalFrom(&payload, msg, proto.MarshalOptions{})
    if err != nil {
        return err
    }

    logger.Log(logging.Entry{
        Payload:  &payload,
        Severity: logging.Info,
    })
    return nil
}

Note: Protobuf payloads cannot be used with the RedirectAsJSON logger option. If you attempt to redirect protobuf payloads, you will receive ErrRedirectProtoPayloadNotSupported.

Nested Structures

You can log complex nested structures:

type Address struct {
    Street  string `json:"street"`
    City    string `json:"city"`
    State   string `json:"state"`
    ZipCode string `json:"zip_code"`
}

type User struct {
    ID        string  `json:"id"`
    Email     string  `json:"email"`
    Address   Address `json:"address"`
    CreatedAt time.Time `json:"created_at"`
}

type UserCreatedEvent struct {
    EventType string    `json:"event_type"`
    User      User      `json:"user"`
    Timestamp time.Time `json:"timestamp"`
}

event := UserCreatedEvent{
    EventType: "user_created",
    User: User{
        ID:    "user-12345",
        Email: "user@example.com",
        Address: Address{
            Street:  "123 Main St",
            City:    "San Francisco",
            State:   "CA",
            ZipCode: "94105",
        },
        CreatedAt: time.Now(),
    },
    Timestamp: time.Now(),
}

logger.Log(logging.Entry{
    Payload:  event,
    Severity: logging.Info,
})

Arrays and Slices

You can include arrays and slices in your payloads:

type BatchProcessingEvent struct {
    BatchID   string   `json:"batch_id"`
    Items     []string `json:"items"`
    Count     int      `json:"count"`
    Processed int      `json:"processed"`
    Failed    int      `json:"failed"`
}

event := BatchProcessingEvent{
    BatchID:   "batch-001",
    Items:     []string{"item-1", "item-2", "item-3"},
    Count:     3,
    Processed: 2,
    Failed:    1,
}

logger.Log(logging.Entry{
    Payload:  event,
    Severity: logging.Info,
})

Combining Payload with Labels

Payloads and Labels serve different purposes:

  • Payload: The main message content (structured data)
  • Labels: Metadata for filtering and searching
type APIRequestEvent struct {
    Method       string        `json:"method"`
    Path         string        `json:"path"`
    StatusCode   int           `json:"status_code"`
    Duration     time.Duration `json:"duration_ms"`
    ResponseSize int64         `json:"response_size"`
}

event := APIRequestEvent{
    Method:       "GET",
    Path:         "/api/users/12345",
    StatusCode:   200,
    Duration:     45 * time.Millisecond,
    ResponseSize: 1024,
}

logger.Log(logging.Entry{
    Payload:  event,
    Severity: logging.Info,
    Labels: map[string]string{
        "service":    "api-gateway",
        "version":    "v2",
        "datacenter": "us-west-2",
    },
})

Error Payloads

When logging errors, include the error information in the payload:

type ErrorPayload struct {
    Error     string `json:"error"`
    Message   string `json:"message"`
    Code      string `json:"code"`
    Timestamp time.Time `json:"timestamp"`
}

err := someOperation()
if err != nil {
    logger.Log(logging.Entry{
        Payload: ErrorPayload{
            Error:     err.Error(),
            Message:   "operation failed",
            Code:      "OP_FAILED",
            Timestamp: time.Now(),
        },
        Severity: logging.Error,
    })
}

Complete Example

package main

import (
    "context"
    "encoding/json"
    "log"
    "time"

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

type OrderEvent struct {
    OrderID     string    `json:"order_id"`
    UserID      string    `json:"user_id"`
    Amount      float64   `json:"amount"`
    Currency    string    `json:"currency"`
    Status      string    `json:"status"`
    CreatedAt   time.Time `json:"created_at"`
    Items       []Item    `json:"items"`
}

type Item struct {
    ProductID string  `json:"product_id"`
    Quantity  int     `json:"quantity"`
    Price     float64 `json:"price"`
}

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("orders")

    // Log structured event
    event := OrderEvent{
        OrderID:   "order-12345",
        UserID:    "user-67890",
        Amount:    109.97,
        Currency:  "USD",
        Status:    "completed",
        CreatedAt: time.Now(),
        Items: []Item{
            {ProductID: "prod-001", Quantity: 2, Price: 29.99},
            {ProductID: "prod-002", Quantity: 1, Price: 49.99},
        },
    }

    logger.Log(logging.Entry{
        Payload:  event,
        Severity: logging.Info,
        Labels: map[string]string{
            "order_type": "online",
            "region":     "us-west",
        },
    })

    // Log raw JSON
    rawJSON := []byte(`{"external_event": "webhook_received", "source": "stripe"}`)
    logger.Log(logging.Entry{
        Payload:  json.RawMessage(rawJSON),
        Severity: logging.Info,
    })

    // Log map payload
    mapPayload := map[string]interface{}{
        "metric":    "response_time",
        "value":     123.45,
        "unit":      "ms",
        "timestamp": time.Now(),
    }

    logger.Log(logging.Entry{
        Payload:  mapPayload,
        Severity: logging.Info,
    })

    logger.Flush()
}

Payload Restrictions

  • The payload must marshal to a JSON object, not other JSON types (arrays, primitives)
  • Invalid UTF-8 characters in strings will cause errors
  • The total size of the entry (including payload) must not exceed the configured limits
  • When using RedirectAsJSON, protobuf payloads are not supported