Configuration
Every setting in one place, with its default. Each one is explained on the page for the type that takes it, and the arguments shared by several types have pages of their own: dims, fields, Field types, Durations, Snapshot options and Flush options.
createHouse
createHouse({
driver,
schema,
delivery,
defaults,
now,
onError,
onWarn,
})| Option | Type | Default | Meaning |
|---|---|---|---|
driver | Driver | required | Where running totals and staged records live |
schema | metrics or a module | none | Registered at startup |
delivery | 'staged', 'immediate', 'auto' | 'staged' | When rows leave |
defaults.flush | duration | none | Cadence for metrics that declare none |
defaults.grace | duration | '2s' | Grace for metrics that declare none |
now | () => number | Date.now | The clock every metric reads |
onError | (error, { metric }) => void | none | Failures that cannot be thrown at a caller |
onWarn | (message, { metric? }) => void | none | Startup warnings about the setup |
Defaults are filled in, never overridden. A metric that declares its own flush keeps it.
counter
The page: counter.
counter(name, { dims, resolution, flush, grace, value, write })| Option | Type | Default | Meaning |
|---|---|---|---|
dims | shape | none | Labels to break the number down by |
resolution | duration | required | How wide one window is |
flush | duration | house default | The fastest this may ship |
grace | duration | house default, then '2s' | How long a window waits for writes on their way |
value | int() or float() | int() | Whether fractions are allowed |
write | WriteFn | required | Where the rows go |
gauge
The page: gauge.
gauge(name, { dims, resolution, flush, grace, aggregate, collect, collectLead, collectScope, write })| Option | Type | Default | Meaning |
|---|---|---|---|
dims | shape | none | Labels to break the value down by |
resolution | duration | required | How wide one window is |
flush | duration | house default | The fastest this may ship |
grace | duration | house default, then '2s' | How long a window waits for observations on their way |
aggregate | array | ['last','min','max','sum','count'] | Which columns reach your sink |
collect | (gauge) => void | Promise<void> | none | Called a little before each window closes, to read a value held elsewhere and set() it |
collectLead | duration | '1s', or a tenth of a shorter resolution | How long before the end of each window the scheduler calls collect |
collectScope | 'fleet' or 'process' | 'fleet' | On a shared driver, one process per window calls collect, or every process does |
write | WriteFn | required | Where the rows go |
collectLead has to be longer than zero and shorter than resolution, and collectLead and collectScope need collect. See Collecting before a window closes for when collect runs.
level
The page: level.
level(name, { dims, resolution, flush, grace, holdFor, value, collect, collectLead, collectScope, write })| Option | Type | Default | Meaning |
|---|---|---|---|
dims | shape | none | Labels to break the value down by |
resolution | duration | required | How wide one window is |
flush | duration | house default | The fastest this may ship |
grace | duration | house default, then '2s' | How long a window waits for writes on their way |
holdFor | duration | forever | How long a series keeps reporting after its last write |
value | float() or int() | float() | Whether fractions are allowed |
collect | (level) => void | Promise<void> | none | Called a little before each window closes, to read a value held elsewhere and set() it |
collectLead | duration | '1s', or a tenth of a shorter resolution | How long before the end of each window the scheduler calls collect |
collectScope | 'fleet' or 'process' | 'fleet' | On a shared driver, one process per window calls collect, or every process does |
write | WriteFn | required | Where the rows go |
holdFor has to be at least one resolution. collectLead has to be longer than zero and shorter than resolution, as on a gauge.
timer
The page: timer.
timer(name, { dims, resolution, flush, grace, aggregate, record, write })| Option | Type | Default | Meaning |
|---|---|---|---|
dims | shape | none | Labels to break the duration down by |
resolution | duration | required | How wide one window is |
flush | duration | house default | The fastest this may ship |
grace | duration | house default, then '2s' | How long a window waits for timings on their way |
aggregate | array | ['min','max','sum','count'] | Which columns reach your sink |
record | event name | none | An event every timing is also written to |
write | WriteFn | required | Where the rows go |
A dimension may not be named duration_ms, ts, _ingested_at or _sample_rate.
event
The page: event.
event(name, { fields, stage, durability, batch, flush, timestamp, sample, derive, claimLimit, write })| Option | Type | Default | Meaning |
|---|---|---|---|
fields | shape | required | The record schema. json() is allowed |
stage | 'driver' or 'local' | 'driver' | Where records wait |
durability | 'relaxed' or 'durable' | 'relaxed' | Whether record() returns at once or a promise that resolves once the driver has the record. 'durable' needs stage: 'driver' and no sample |
batch.maxSize | number | 500 | Local staging: ship at this many |
batch.maxAge | duration | '10s' | Local staging: ship this long after the first |
batch.maxStaged | number | 100_000, or batch.maxSize when larger | Local staging: the most records this process holds before it refuses more |
flush | duration | the house default, then '30s' | The fastest this may ship |
timestamp | 'auto' or a ts() field | 'auto' | Where ts comes from |
sample | number or function | keep everything | The fraction to keep, 0 to 1 |
derive | record of functions | none | Counters this event also increments |
claimLimit | number | unlimited | Records one claim, and one call to write, may carry. A flush claims again while a claim comes back full |
write | WriteFn | required | Where the rows go |
A field may not be named id, ts, _ingested_at or _sample_rate.
log
The page: log.
log(name, { fields, levels, minLevel, stage, batch, flush, claimLimit, write })| Option | Type | Default | Meaning |
|---|---|---|---|
fields | shape | none | Extra fields beyond the reserved ones |
levels | array of strings | ['debug','info','warn','error'] | Ascending severity |
minLevel | one of levels | the lowest | Drop anything below this |
stage | 'driver' or 'local' | 'driver' | Where lines wait |
batch.maxSize | number | 500 | Local staging: ship at this many |
batch.maxAge | duration | '10s' | Local staging: ship this long after the first |
batch.maxStaged | number | 100_000, or batch.maxSize when larger | Local staging: the most records this process holds before it refuses more |
flush | duration | the house default, then '30s' | The fastest this may ship |
claimLimit | number | unlimited | Lines one claim, and one call to write, may carry. A flush claims again while a claim comes back full |
write | WriteFn | required | Where the rows go |
A field may not be named id, ts, level, message, error_stack, _ingested_at or _sample_rate. A level may not shadow a method on the logger.
memory
memory({ maxSeries, maxStaged })| Option | Type | Default | Meaning |
|---|---|---|---|
maxSeries | number | 100_000 | Distinct label combinations per metric |
maxStaged | number | 100_000 | Staged records per metric |
Each has to be a positive whole number, or the driver throws when it is created. Set either to Number.POSITIVE_INFINITY to disable. Leave them on. They turn a runaway dimension into a loud error instead of a crash with no warning.
ioredis
ioredis(clientOrFactory, { namespace, maxPipelineSize, recoverAfter })| Option | Type | Default | Meaning |
|---|---|---|---|
namespace | string | 'mh' | Key prefix, with no colon, no whitespace and no half of a surrogate pair. Two houses sharing one Redis need different ones |
maxPipelineSize | number | 1000 | Commands or Lua scripts per round trip. A positive whole number, or the driver throws when it is created |
recoverAfter | duration | '5m' | How long a claim may be held before a flush treats it as abandoned |
Pass a function rather than a client to delay connecting until the first write. A client made that way belongs to the driver, so close it with driver.close() after house.stop(). A client you pass in yourself is yours to close.
Keep recoverAfter above your sink's timeout. It is what separates a flusher that crashed from one that is merely slow, and taking a claim back from a slow one ships those rows twice. See Recovering a crashed flush.
Durations
Every time based setting takes a whole number followed by a lowercase unit, or a plain number of milliseconds.
'500ms' '30s' '5m' '2h' '7d' 5_000Durations has the units, the rejected inputs and the rule that resolution must divide flush.
Flush options
metric.flush({ force })
house.flush({ force, only, strict })| Option | Type | Default | Meaning |
|---|---|---|---|
force | boolean | false | Ignore the cadence and ship everything finished |
only | array of names | every metric | Restrict the flush to these metrics. House only |
strict | boolean | false | Reject an only naming a metric the house does not hold. House only |
Flush options also covers every field of the report that comes back.
Snapshot options
metric.snapshot({ dims, from, to, complete, rollup, groupBy, orderBy, direction, limit })
house.snapshot({ only, strict, ...theSame })| Option | Type | Default | Meaning |
|---|---|---|---|
dims | partial values | none | Match on declared dimensions |
from | number or Date | none | Lower bound on the window, inclusive |
to | number or Date | none | Upper bound, exclusive |
complete | boolean | true | Exclude the window still filling |
rollup | 'none' or 'sum' | 'none' | Merge every window of a series into one row |
groupBy | array of dimension names | every dimension | Collapse to these |
orderBy | column name | none | Sort before limit applies |
direction | 'asc' or 'desc' | 'desc' | Sort direction |
limit | number | none | Take this many, after sorting |
only | array of names | every metric | House only |
strict | boolean | false | Reject an only naming a metric the house does not hold. House only |
Snapshot options covers what each metric type does with them, and how the row type follows.
Validation that runs at startup
These all throw when the module is first imported, not at the first write.
| Check | Message |
|---|---|
| Empty metric name | counter: name must be a non-empty string |
| A colon or whitespace in a metric name | name "e:checkout" may not contain a colon or whitespace |
| Half of a surrogate pair in a metric name | name "a\ud800" holds half of a surrogate pair |
A metric named __proto__ | a metric cannot be named "__proto__" |
No write function | sold: write must be a function that stores the rows, got undefined |
A oneOf whose members print the same | oneOf: "2" prints the same as another member |
A json() default JSON cannot hold | default for json(): json() needs a value JSON can hold |
json() as a dimension | dim "x" declares json(), which cannot be encoded into a series key |
| Resolution does not divide flush | sold: resolution 7s does not divide flush 1m evenly |
A zero flush, defaults.flush or batch.maxAge | flush must be longer than zero, got "0s" |
A flush, defaults.flush or batch.maxAge past 2147483647ms | flush is 30d, longer than 2147483647ms (just under 25 days) |
| Invalid duration | parseDuration: "1.5m" |
| Bad default value | default for int(): expected a safe integer, got "five" |
| Unknown gauge aggregate | unknown aggregate "avg" |
A collect that is not a function | q: collect must be a function, got string |
A collectLead of zero | q: collectLead must be longer than zero, got "0s" |
A collectLead as long as resolution or longer | q: collectLead is 1m, and it must be shorter than the resolution, 1m |
A collectLead that is not a duration | q: collectLead: parseDuration: "1.5s" |
An unknown collectScope | q: collectScope must be 'fleet' or 'process', got "cluster" |
collectLead or collectScope without collect | q: collectLead is set, but collect is not, so nothing would run |
| A gauge aggregate named twice | aggregate names ["sum","sum"], and each one may appear once |
| A dim named after a column the metric writes | dim "id" is a reserved column |
| A dim or field named like a whole number | a dim cannot be named "2024" |
A dim or field named bucket_open or bucket_elapsed_ms | a dim cannot be named "bucket_open" |
An unknown event stage, null included | stage must be 'driver' or 'local', got "memory" |
A batch.maxStaged that is not a positive whole number | batch.maxStaged must be a positive integer, got 0 |
A batch.maxStaged below batch.maxSize | batch.maxStaged (9) must be at least batch.maxSize (10) |
An unknown event durability | durability must be 'relaxed' or 'durable', got "always" |
durability: 'durable' with stage: 'local' | durability 'durable' needs stage 'driver' |
durability: 'durable' with sample | durability 'durable' cannot sample |
A sample that is neither a number nor a function | sample must be a rate between 0 and 1 or a function returning one |
| Reserved event field name | field "ts" is a reserved column |
| Duplicate level | level "info" is declared twice |
minLevel not in levels | minLevel "trace" is not one of the declared levels |
A level shadowing a method, or named then | level "flush" would shadow an existing property on the logger |
A timer dimension named duration_ms | dim "duration_ms" is reserved |
A timer dimension named after a column its record event writes | dim "ts" is reserved, because a record event writes a column of that name on every row |
| Two metrics with the same name | createHouse: two metrics are both named "x" |
| A metric registered with a second house | already bound to a house |
| No cadence anywhere | no flush cadence. Declare flush on the counter, or defaults.flush on the house |
An unknown delivery | createHouse: delivery must be 'staged', 'immediate' or 'auto', got "immedate" |