Elapsed
Measure and log the elapsed duration of an operation without animations:
e := clog.Info().Elapsed("elapsed")
runMigrations()
e.Msg("database migration")
// INF ℹ️ database migration elapsed=2s
Use Elapsed when you want elapsed-time logging but don’t need a spinner, progress bar, or any visual animation. The elapsed field uses the same formatting, styling, and field type as animation Elapsed fields.
Finalising
Elapsed events can be finalised with Send (no message), Msg, or Msgf:
e := clog.Info().Elapsed("elapsed")
runMigrations()
e.Send()
// INF ℹ️ elapsed=2s
e = clog.Info().Elapsed("elapsed")
runMigrations()
e.Msg("migrations complete")
// INF ℹ️ migrations complete elapsed=2s
Field Positioning
Elapsed can appear anywhere in the field chain to control where the elapsed field is shown:
// Elapsed before other fields
e := clog.Info().Elapsed("elapsed").Str("env", "prod")
deploy()
e.Msg("deploy")
// INF ℹ️ deploy elapsed=12s env=prod
// Elapsed after other fields
e = clog.Info().Str("env", "prod").Elapsed("elapsed")
deploy()
e.Msg("deploy")
// INF ℹ️ deploy env=prod elapsed=12s
On animated builders (fx.Builder), fields added at runtime via a live update always render after the builder’s base fields - use elapsed.Trailing() to pin the elapsed field to the end of the row regardless (see Spinner).
Custom Key
The key parameter controls the field name:
e := clog.Info().Elapsed("duration")
compile()
e.Msg("compile")
// INF ℹ️ compile duration=3s
Log Levels
Since Elapsed is a method on events, you control the level directly:
clog.Warn().Elapsed("elapsed").Msg("slow query")
// WRN ⚠️ slow query elapsed=5s
clog.Error().Elapsed("elapsed").Err(err).Msg("compile")
// ERR ❌ compile elapsed=3s error="syntax error"
Sub-loggers
Elapsed works on any logger instance:
logger := clog.With().Str("component", "db").Logger()
e := logger.Info().Elapsed("elapsed")
runQuery()
e.Msg("query")
// INF ℹ️ query component=db elapsed=1s
Elapsed Configuration
The elapsed field respects the same per-logger FieldFormats configuration as animation elapsed fields:
| Field | Default | Description |
|---|---|---|
DurationFormat | nil (built-in) | Custom formatter for both Duration and Elapsed fields |
DurationGradientMax | 0 (disabled) | Max duration for Duration field gradient (see Styles) |
DurationMinimum | time.Second | Hide Duration fields below this threshold (0 shows all values) |
DurationPrecision | 0 | Decimal places for Duration fields (0 = 3s, 1 = 3.2s) |
DurationRound | time.Second | Rounding granularity for Duration fields (0 disables rounding) |
ElapsedFormat | nil (built-in) | Custom formatter for elapsed durations (takes priority over DurationFormat) |
ElapsedGradientMax | 0 (disabled) | Max duration for gradient coloring (see Styles) |
ElapsedMinimum | time.Second | Hide elapsed field below this threshold (0 shows all values) |
ElapsedPrecision | 0 | Decimal places (0 = 3s, 1 = 3.2s) |
ElapsedRound | time.Second | Rounding granularity (0 disables rounding) |
ElapsedGradientMax, ElapsedMinimum, and the ElapsedGradient/ElapsedGradientMode style settings, can also be overridden per field with options from the elapsed package - see Per-Field Overrides. The duration package mirrors this for Duration fields, including duration.WithMinimum:
import "github.com/gechr/clog/field/elapsed"
e := clog.Info().Elapsed("elapsed",
elapsed.WithGradientMax(5*time.Second),
elapsed.WithMinimum(0), // always show this field, regardless of the logger default
)
runMigrations()
e.Msg("database migration")
Duration Format Function
DurationFormat configures a single format function that applies to both Duration fields and Elapsed fields. This is useful when you have a shared helper (e.g. from a utility package) that you want applied consistently across all duration logging:
f := clog.DefaultFieldFormats()
f.DurationFormat = commonutil.FormatDuration
clog.SetFieldFormats(f)
// Both of these now use commonutil.FormatDuration:
clog.Info().Duration("took", time.Since(start)).Msg("done")
// INF ℹ️ done took=2.3s
e := clog.Info().Elapsed("elapsed")
doWork()
e.Msg("done")
// INF ℹ️ done elapsed=2.3s
When ElapsedFormat is also set, it takes priority over DurationFormat for Elapsed fields only. Duration fields always use DurationFormat:
f := clog.DefaultFieldFormats()
f.DurationFormat = func(d time.Duration) string { return "dur:" + d.String() }
f.ElapsedFormat = func(d time.Duration) string { return "ela:" + d.String() }
clog.SetFieldFormats(f)
clog.Info().Duration("latency", 3*time.Second).Msg("request")
// INF ℹ️ request latency=dur:3s ← uses DurationFormat
e := clog.Info().Elapsed("elapsed")
e.Msg("done")
// INF ℹ️ done elapsed=ela:3s ← ElapsedFormat takes priority