Styles
Customise the visual appearance using lipgloss styles:

styles := clog.DefaultStyles()
// Customise level colours
styles.Levels[clog.ErrorLevel] = new(
lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("9")), // bright red
)
// Customise field key appearance
styles.KeyDefault = new(
lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("12")), // bright blue
)
clog.SetStyles(styles)
Value Colouring
Values are styled with a three-tier priority system:
- Key styles - style all values of a specific field key
- Value styles - style values matching a typed key (bool
true!= string"true") - Type styles - style values by their Go type
styles := clog.DefaultStyles()
// 1. Key styles: all values of the "status" field are green
styles.Keys["status"] = new(lipgloss.NewStyle().
Foreground(lipgloss.Color("2"))) // green
// 2. Value styles: typed key matches (bool `true` != string "true")
styles.Values["PASS"] = new(
lipgloss.NewStyle().
Foreground(lipgloss.Color("2")), // green
)
styles.Values["FAIL"] = new(lipgloss.NewStyle().
Foreground(lipgloss.Color("1")), // red
)
// 3. Type styles: string values -> white, numeric values -> magenta, errors -> red by default
styles.FieldString = new(lipgloss.NewStyle().Foreground(lipgloss.Color("15")))
styles.FieldNumber = new(lipgloss.NewStyle().Foreground(lipgloss.Color("5")))
styles.FieldError = new(lipgloss.NewStyle().Foreground(lipgloss.Color("1")))
styles.FieldString = nil // set to nil to disable
styles.FieldNumber = nil // set to nil to disable
clog.SetStyles(styles)
Styles Reference
| Field | Type | Alias | Default |
|---|---|---|---|
DurationThresholds | map[string][]Threshold | ThresholdMap | {} |
DurationUnits | map[string]Style | StyleMap | {} |
FieldDurationNumber | Style | magenta | |
FieldDurationUnit | Style | magenta faint | |
FieldElapsedNumber | Style | nil (→ DurationNumber) | |
FieldElapsedUnit | Style | nil (→ DurationUnit) | |
FieldError | Style | red | |
FieldJSON | *JSONStyles | DefaultJSONStyles() | |
FieldNumber | Style | magenta | |
FieldPercent | Style | nil | |
FieldQuantityNumber | Style | magenta | |
FieldQuantityUnit | Style | magenta faint | |
FieldString | Style | white | |
FieldTime | Style | magenta | |
KeyDefault | Style | blue | |
Keys | map[string]Style | StyleMap | {} |
Levels | map[Level]Style | LevelStyleMap | per-level bold colours |
Messages | map[Level]Style | LevelStyleMap | DefaultMessageStyles() |
Prefixes | map[Level]Style | LevelStyleMap | {} |
PercentGradient | []ColorStop | red → yellow → green | |
QuantityThresholds | map[string][]Threshold | ThresholdMap | {} |
QuantityUnits | map[string]Style | StyleMap | {} |
Separator | Style | faint | |
Timestamp | Style | faint | |
Values | map[any]Style | ValueStyleMap | DefaultValueStyles() |
| Field | Description |
|---|---|
DurationThresholds | Duration unit -> magnitude-based style thresholds |
DurationUnits | Duration unit string -> style override |
FieldDurationNumber | Style for numeric segments of duration values (e.g. “1” in “1m30s”), nil to disable |
FieldDurationUnit | Style for unit segments of duration values (e.g. “m” in “1m30s”), nil to disable |
FieldElapsedNumber | Style for numeric segments of elapsed-time values; nil falls back to FieldDurationNumber |
FieldElapsedUnit | Style for unit segments of elapsed-time values; nil falls back to FieldDurationUnit |
FieldError | Style for error field values, nil to disable |
FieldJSON | Per-token styles for JSON syntax highlighting; nil disables highlighting |
FieldNumber | Style for int/float field values, nil to disable |
FieldPercent | Base style for Percent fields (foreground overridden by gradient), nil to disable |
FieldQuantityNumber | Style for numeric part of quantity values (e.g. “5” in “5km”), nil to disable |
FieldQuantityUnit | Style for unit part of quantity values (e.g. “km” in “5km”), nil to disable |
FieldString | Style for string field values, nil to disable |
FieldTime | Style for time.Time field values, nil to disable |
KeyDefault | Style for field key names without a per-key override, nil to disable |
Keys | Field key name -> value style override |
Levels | Per-level label style (e.g. “INF”, “ERR”), nil to disable |
Messages | Per-level message text style, nil to disable |
Prefixes | Per-level prefix style |
PercentGradient | Gradient colour stops for Percent fields |
QuantityThresholds | Quantity unit -> magnitude-based style thresholds |
QuantityUnits | Quantity unit string -> style override |
Separator | Style for the separator between key and value |
Timestamp | Style for the timestamp prefix, nil to disable |
Values | Typed value -> style (uses Go equality, so bool true != string "true") |
Configuration
Behavioural settings are configured via setter methods on Logger (or package-level convenience functions for the Default logger):
| Setter | Type | Default | Description |
|---|---|---|---|
SetAnimationInterval | time.Duration | 67ms | Minimum refresh interval for all animations (0 = use built-in rates) |
SetElapsedFormatFunc | func(time.Duration) string | nil | Custom format function for Elapsed fields |
SetElapsedMinimum | time.Duration | time.Second | Minimum duration for Elapsed fields to be displayed |
SetElapsedPrecision | int | 0 | Decimal places for Elapsed display (0 = “3s”, 1 = “3.2s”) |
SetElapsedRound | time.Duration | time.Second | Rounding granularity for Elapsed values (0 to disable) |
SetFieldSort | Sort | SortNone | Sort order: SortNone, SortAscending, SortDescending |
SetPercentFormatFunc | func(float64) string | nil | Custom format function for Percent fields |
SetPercentReverseGradient | bool | false | Reverse the percent gradient (green=0%, red=100%) for this logger |
SetPercentPrecision | int | 0 | Decimal places for Percent display (0 = “75%”, 1 = “75.0%”) |
SetQuantityUnitsIgnoreCase | bool | true | Case-insensitive quantity unit matching |
SetSeparatorText | string | "=" | Key/value separator string |
Each Threshold pairs a minimum value with style overrides:
type ThresholdStyle struct {
Number Style // Override for the number segment (nil = keep default).
Unit Style // Override for the unit segment (nil = keep default).
}
type Threshold struct {
Value float64 // Minimum numeric value (inclusive) to trigger this style.
Style ThresholdStyle // Style overrides for number and unit segments.
}
Thresholds are evaluated in descending order - the first match wins:
styles.QuantityThresholds["ms"] = clog.Thresholds{
{Value: 5000, Style: clog.ThresholdStyle{Number: redStyle, Unit: redStyle}},
{Value: 1000, Style: clog.ThresholdStyle{Number: yellowStyle, Unit: yellowStyle}},
}
Value styles only apply at Info level and above by default. Use SetFieldStyleLevel to change the threshold.
Per-Level Message Styles
Style the log message text differently for each level:
styles := clog.DefaultStyles()
styles.Messages[clog.ErrorLevel] = new(
lipgloss.NewStyle().Foreground(lipgloss.Color("1")), // red
)
styles.Messages[clog.WarnLevel] = new(
lipgloss.NewStyle().Foreground(lipgloss.Color("3")), // yellow
)
clog.SetStyles(styles)
Use DefaultMessageStyles() to get the defaults (unstyled for all levels).
Use DefaultValueStyles() to get the default value styles (true=green, false=red, nil=grey, ""=grey).
Use DefaultPercentGradient() to get the default red → yellow → green gradient stops used for Percent fields.
Percent Gradient Direction
By default the Percent gradient runs red (0%) → yellow (50%) → green (100%) - useful when a higher value is better (e.g. battery, health score). For metrics where a lower value is better (CPU usage, disk usage, error rate), reverse the gradient:
// Global: all Percent fields on the Default logger
clog.SetPercentReverseGradient(true)
// Per-logger: all Percent fields on this logger
logger.SetPercentReverseGradient(true)
// Per-field: just this Percent field, regardless of logger setting
clog.Info().
Percent("cpu", 92, clog.WithPercentReverseGradient()).
Percent("battery", 85).
Msg("System status")
// "cpu" renders red at 92%, "battery" renders green at 85%
WithPercentReverseGradient() is a PercentOption passed directly to Event.Percent. It toggles the logger-level setting for that field - so if the logger already has the gradient reversed, WithPercentReverseGradient() flips it back to normal. This makes it easy to mix metrics with different semantics on the same log line regardless of the logger default.
Format Hooks
Override the default formatting for Elapsed and Percent fields:
// Custom elapsed format: truncate to whole seconds
clog.SetElapsedFormatFunc(func(d time.Duration) string {
return d.Truncate(time.Second).String()
})
// Custom percent format: "75/100" instead of "75%"
clog.SetPercentFormatFunc(func(v float64) string {
return fmt.Sprintf("%.0f/100", v)
})
When set to nil (the default), the built-in formatters are used (formatElapsed with SetElapsedPrecision for elapsed, strconv.FormatFloat with SetPercentPrecision + “%” for percent).
Field Sort Order
Control the order fields appear in log output. By default fields preserve insertion order.
// Sort fields alphabetically by key
clog.SetFieldSort(clog.SortAscending)
// Or reverse alphabetical
clog.SetFieldSort(clog.SortDescending)
| Constant | Description |
|---|---|
SortNone | Preserve insertion order (default) |
SortAscending | Sort fields by key A→Z |
SortDescending | Sort fields by key Z→A |
clog.Info().
Str("zoo", "animals").
Str("alpha", "first").
Int("count", 42).
Msg("Sorted")
// SortNone: INF ℹ️ Sorted zoo=animals alpha=first count=42
// SortAscending: INF ℹ️ Sorted alpha=first count=42 zoo=animals
// SortDescending: INF ℹ️ Sorted zoo=animals count=42 alpha=first
Renderer Binding
Styles created with lipgloss.NewStyle() are bound to the global renderer (anchored to os.Stdout). When stdout is piped, that renderer detects Ascii profile and all colours are silently stripped - even for styles meant for stderr.
clog handles this automatically: New, SetStyles, SetOutput, and SetColorMode all call WithRenderer to rebind styles to the logger’s output renderer. Custom styles passed to SetStyles are transparently rebound - no changes needed in user code.
For advanced use, Styles and JSONStyles expose WithRenderer(*lipgloss.Renderer):
styles := clog.DefaultStyles()
styles.WithRenderer(output.Renderer())
Both methods mutate and return the receiver for fluent chaining.