tessl install tessl/golang-cloud-google-com--go--logging@1.13.0Cloud Logging client library for Go that enables writing log entries to Google Cloud Logging service with buffered asynchronous and synchronous logging capabilities.
This document describes the different payload types supported by Cloud Logging entries and how to use them.
type Entry struct {
// ...
Payload interface{}
// ...
}The Payload field of an Entry can be:
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,
})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
}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,
})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,
})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,
})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:
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.
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,
})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,
})Payloads and Labels serve different purposes:
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",
},
})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,
})
}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()
}RedirectAsJSON, protobuf payloads are not supported