or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

fields.mdindex.mdintegrations.mdlogger.mdtesting.mdzapcore.md
tile.json

fields.mddocs/

Structured Fields API

This document covers all field constructor functions for structured logging. Fields provide efficient, zero-allocation, strongly-typed structured data for log entries.

Field Type

type Field = zapcore.Field

Fields are the core building blocks for structured logging in zap. Each field represents a key-value pair that will be included in log output.

Primitive Types

Boolean Fields

func Bool(key string, val bool) Field
func Boolp(key string, val *bool) Field
func Bools(key string, bs []bool) Field

Integer Fields

// int types
func Int(key string, val int) Field
func Intp(key string, val *int) Field
func Ints(key string, nums []int) Field

// int8 types
func Int8(key string, val int8) Field
func Int8p(key string, val *int8) Field
func Int8s(key string, nums []int8) Field

// int16 types
func Int16(key string, val int16) Field
func Int16p(key string, val *int16) Field
func Int16s(key string, nums []int16) Field

// int32 types
func Int32(key string, val int32) Field
func Int32p(key string, val *int32) Field
func Int32s(key string, nums []int32) Field

// int64 types
func Int64(key string, val int64) Field
func Int64p(key string, val *int64) Field
func Int64s(key string, nums []int64) Field

Unsigned Integer Fields

// uint types
func Uint(key string, val uint) Field
func Uintp(key string, val *uint) Field
func Uints(key string, nums []uint) Field

// uint8 types
func Uint8(key string, val uint8) Field
func Uint8p(key string, val *uint8) Field
func Uint8s(key string, nums []uint8) Field

// uint16 types
func Uint16(key string, val uint16) Field
func Uint16p(key string, val *uint16) Field
func Uint16s(key string, nums []uint16) Field

// uint32 types
func Uint32(key string, val uint32) Field
func Uint32p(key string, val *uint32) Field
func Uint32s(key string, nums []uint32) Field

// uint64 types
func Uint64(key string, val uint64) Field
func Uint64p(key string, val *uint64) Field
func Uint64s(key string, nums []uint64) Field

// uintptr types
func Uintptr(key string, val uintptr) Field
func Uintptrp(key string, val *uintptr) Field
func Uintptrs(key string, nums []uintptr) Field

Floating-Point Fields

// float32 types
func Float32(key string, val float32) Field
func Float32p(key string, val *float32) Field
func Float32s(key string, nums []float32) Field

// float64 types
func Float64(key string, val float64) Field
func Float64p(key string, val *float64) Field
func Float64s(key string, nums []float64) Field

Complex Number Fields

// complex64 types
func Complex64(key string, val complex64) Field
func Complex64p(key string, val *complex64) Field
func Complex64s(key string, nums []complex64) Field

// complex128 types
func Complex128(key string, val complex128) Field
func Complex128p(key string, val *complex128) Field
func Complex128s(key string, nums []complex128) Field

String Fields

// UTF-8 string
func String(key string, val string) Field
func Stringp(key string, val *string) Field
func Strings(key string, ss []string) Field

// UTF-8 encoded byte slice (for textual data)
func ByteString(key string, val []byte) Field
func ByteStrings(key string, bss [][]byte) Field

// Binary data (for opaque byte blobs)
func Binary(key string, val []byte) Field

ByteString vs Binary: Use ByteString for UTF-8 encoded text that happens to be in a byte slice. Use Binary for truly opaque binary data. Encoders may base64-encode binary data but log byte strings as text.

Time Fields

// time.Time
func Time(key string, val time.Time) Field
func Timep(key string, val *time.Time) Field
func Times(key string, ts []time.Time) Field

// time.Duration
func Duration(key string, val time.Duration) Field
func Durationp(key string, val *time.Duration) Field
func Durations(key string, ds []time.Duration) Field

Error Fields

// Standard error field (key is "error")
func Error(err error) Field

// Error with custom key
func NamedError(key string, err error) Field

// Multiple errors
func Errors(key string, errs []error) Field

The Error function is shorthand for NamedError("error", err). Error fields lazily call err.Error() only when the log entry is actually written.

Advanced Fields

Any Field

func Any(key string, value interface{}) Field

Any automatically chooses the best field type for the value. It supports all primitive types, errors, stringers, and falls back to reflection for unknown types. Use specific field constructors when possible for better performance.

Object and Array Fields

// Custom object marshaling
func Object(key string, val zapcore.ObjectMarshaler) Field

// Array of objects
func Objects[T zapcore.ObjectMarshaler](key string, values []T) Field

// Array of objects with pointer receivers
func ObjectValues[T any, P ObjectMarshalerPtr[T]](key string, values []T) Field

// Custom array marshaling
func Array(key string, val zapcore.ArrayMarshaler) Field

These fields allow custom types to implement efficient marshaling:

type User struct {
    ID   int
    Name string
}

func (u User) MarshalLogObject(enc zapcore.ObjectEncoder) error {
    enc.AddInt("id", u.ID)
    enc.AddString("name", u.Name)
    return nil
}

logger.Info("user created", zap.Object("user", user))

Dictionary Fields

// Create nested object from fields
func Dict(key string, val ...Field) Field

// Helper to create ObjectMarshaler from fields
func DictObject(val ...Field) zapcore.ObjectMarshaler

Dictionary fields create nested objects in structured output:

logger.Info("request processed",
    zap.Dict("request",
        zap.String("method", "GET"),
        zap.String("path", "/api/users"),
        zap.Int("status", 200),
    ),
)
// JSON output includes nested "request": {"method": "GET", ...}

Inline Fields

func Inline(val zapcore.ObjectMarshaler) Field

Inline fields merge an object's fields directly into the parent, without creating a nested object:

type RequestContext struct {
    RequestID string
    UserID    int
}

func (rc RequestContext) MarshalLogObject(enc zapcore.ObjectEncoder) error {
    enc.AddString("request_id", rc.RequestID)
    enc.AddInt("user_id", rc.UserID)
    return nil
}

logger.Info("processing", zap.Inline(ctx))
// Fields appear at top level: {"msg": "processing", "request_id": "...", "user_id": ...}

Reflection Field

func Reflect(key string, val interface{}) Field

Reflect uses Go's reflection to serialize arbitrary values. This is slower and should be avoided in hot paths. Prefer Object, Array, or specific field types when possible.

Stringer Field

func Stringer(key string, val fmt.Stringer) Field
func Stringers[T fmt.Stringer](key string, values []T) Field

Stringer calls the String() method on values implementing fmt.Stringer. The call is deferred until the log entry is written.

Stringers constructs a field for a slice of fmt.Stringer values, calling String() on each element. Note that these objects must implement fmt.Stringer directly on the value type, not the pointer type.

Stack Trace Fields

// Capture stack trace
func Stack(key string) Field

// Capture stack trace skipping N frames
func StackSkip(key string, skip int) Field

Stack trace fields capture the current goroutine's stack and include it in the log output. Use skip to omit wrapper functions from the trace.

Namespace Field

func Namespace(key string) Field

Namespace creates an isolated scope for subsequent fields, useful for grouping related fields in nested objects:

logger.Info("transaction",
    zap.Namespace("request"),
    zap.String("method", "POST"),
    zap.String("path", "/api/users"),
    zap.Namespace("response"),
    zap.Int("status", 201),
    zap.Duration("latency", 45*time.Millisecond),
)
// Creates nested structure with "request" and "response" objects

Skip Field

func Skip() Field

Skip constructs a no-op field, which is often useful when handling invalid inputs in other field constructors. It can be used in conditional logic where you need to return a field but don't want to log anything:

func getUserField(user *User) zap.Field {
    if user == nil {
        return zap.Skip()
    }
    return zap.Object("user", user)
}

ObjectMarshalerPtr Type

type ObjectMarshalerPtr[T any] interface {
    *T
    zapcore.ObjectMarshaler
}

Helper constraint for ObjectValues to handle types with pointer receiver marshaling methods.

Field Usage Examples

Basic Field Usage

logger.Info("user login",
    zap.String("username", "alice"),
    zap.Int("user_id", 12345),
    zap.Bool("admin", false),
    zap.Duration("session_duration", 2*time.Hour),
)

Error Logging

if err != nil {
    logger.Error("failed to save user",
        zap.Error(err),
        zap.String("username", username),
        zap.Int("attempt", retryCount),
    )
}

// Multiple errors
logger.Error("batch operation failed",
    zap.Errors("errors", errorList),
)

Pointer Fields

var count *int = nil
logger.Info("stats", zap.Intp("count", count))  // Logs null for nil pointer

value := 42
logger.Info("stats", zap.Intp("count", &value))  // Logs 42

Array Fields

tags := []string{"api", "production", "critical"}
logger.Info("alert", zap.Strings("tags", tags))

values := []int{1, 2, 3, 4, 5}
logger.Debug("values", zap.Ints("values", values))

Time Fields

startTime := time.Now()
// ... do work ...
duration := time.Since(startTime)

logger.Info("operation completed",
    zap.Time("start_time", startTime),
    zap.Duration("duration", duration),
)

Complex Nested Structures

type Address struct {
    Street string
    City   string
}

func (a Address) MarshalLogObject(enc zapcore.ObjectEncoder) error {
    enc.AddString("street", a.Street)
    enc.AddString("city", a.City)
    return nil
}

type Person struct {
    Name    string
    Age     int
    Address Address
}

func (p Person) MarshalLogObject(enc zapcore.ObjectEncoder) error {
    enc.AddString("name", p.Name)
    enc.AddInt("age", p.Age)
    enc.AddObject("address", p.Address)
    return nil
}

person := Person{
    Name: "Alice",
    Age:  30,
    Address: Address{
        Street: "123 Main St",
        City:   "Springfield",
    },
}

logger.Info("person details", zap.Object("person", person))
// Produces nested JSON structure

Using Dict for Ad-hoc Nested Objects

logger.Info("http request",
    zap.String("method", "POST"),
    zap.Dict("headers",
        zap.String("content-type", "application/json"),
        zap.String("user-agent", "MyApp/1.0"),
    ),
    zap.Dict("response",
        zap.Int("status", 200),
        zap.Duration("latency", 45*time.Millisecond),
    ),
)

Using Any for Unknown Types

var value interface{} = getUserInput()

logger.Info("received value",
    zap.Any("value", value),  // Automatically determines correct field type
)

// More efficient when type is known:
if str, ok := value.(string); ok {
    logger.Info("received value", zap.String("value", str))
}

Inline for Flat Context

type RequestContext struct {
    TraceID   string
    SpanID    string
    UserID    string
}

func (rc RequestContext) MarshalLogObject(enc zapcore.ObjectEncoder) error {
    enc.AddString("trace_id", rc.TraceID)
    enc.AddString("span_id", rc.SpanID)
    enc.AddString("user_id", rc.UserID)
    return nil
}

ctx := RequestContext{
    TraceID: "abc123",
    SpanID:  "def456",
    UserID:  "user789",
}

// Inline merges fields at top level
logger.Info("request received", zap.Inline(ctx))
// Produces: {"msg": "request received", "trace_id": "abc123", "span_id": "def456", "user_id": "user789"}

// Without Inline, creates nested object
logger.Info("request received", zap.Object("context", ctx))
// Produces: {"msg": "request received", "context": {"trace_id": "abc123", "span_id": "def456", "user_id": "user789"}}

Stack Traces

// Capture stack trace on errors
logger.Error("unexpected condition",
    zap.Error(err),
    zap.Stack("stacktrace"),
)

// Skip wrapper functions
func LogError(msg string, err error) {
    logger.Error(msg,
        zap.Error(err),
        zap.StackSkip("stacktrace", 1),  // Skip this wrapper function
    )
}

Performance Considerations

  1. Use specific field constructors: zap.String(), zap.Int(), etc. are faster than zap.Any() or zap.Reflect()

  2. Avoid reflection: zap.Reflect() is slow. Implement ObjectMarshaler or ArrayMarshaler for custom types

  3. Lazy evaluation: Error fields, Stringer fields, and Object/Array fields defer work until the log is actually written

  4. Pointer fields: The *p variants (e.g., zap.Intp()) add overhead but handle nil correctly

  5. Zero allocations: Most field constructors make zero allocations, making zap suitable for hot paths

Field Categories Summary

CategoryUse CaseExamples
PrimitivesNumbers, booleansInt, Float64, Bool
StringsText dataString, ByteString
TimeTimestamps, durationsTime, Duration
ErrorsError valuesError, NamedError, Errors
ObjectsComplex typesObject, Dict, Inline
ArraysSlicesInts, Strings, Objects
AdvancedUnknown/dynamic typesAny, Reflect
MetaStructure/debuggingNamespace, Stack