@venizia/ignis-docs 0.2.0 → 0.2.1-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -14
- package/content/best-practices/api-usage-examples.md +39 -19
- package/content/best-practices/architectural-patterns.md +24 -13
- package/content/best-practices/architecture-decisions.md +29 -16
- package/content/best-practices/code-style-standards/advanced-patterns.md +43 -31
- package/content/best-practices/code-style-standards/constants-configuration.md +19 -4
- package/content/best-practices/code-style-standards/control-flow.md +33 -1
- package/content/best-practices/code-style-standards/documentation.md +28 -8
- package/content/best-practices/code-style-standards/function-patterns.md +15 -4
- package/content/best-practices/code-style-standards/index.md +7 -2
- package/content/best-practices/code-style-standards/naming-conventions.md +27 -3
- package/content/best-practices/code-style-standards/route-definitions.md +9 -5
- package/content/best-practices/code-style-standards/tooling.md +14 -1
- package/content/best-practices/code-style-standards/type-safety.md +39 -6
- package/content/best-practices/common-pitfalls.md +59 -35
- package/content/best-practices/contribution-workflow.md +8 -4
- package/content/best-practices/data-modeling.md +78 -62
- package/content/best-practices/deployment-strategies.md +56 -19
- package/content/best-practices/error-handling.md +247 -153
- package/content/best-practices/index.md +6 -0
- package/content/best-practices/performance-optimization.md +26 -13
- package/content/best-practices/security-guidelines.md +35 -9
- package/content/best-practices/testing-strategies.md +7 -2
- package/content/best-practices/troubleshooting-tips.md +27 -17
- package/content/extensions/components/api-reference.md +109 -323
- package/content/extensions/components/authentication/api.md +489 -602
- package/content/extensions/components/authentication/errors.md +135 -498
- package/content/extensions/components/authentication/index.md +89 -801
- package/content/extensions/components/authentication/usage.md +231 -955
- package/content/extensions/components/authorization/api.md +991 -644
- package/content/extensions/components/authorization/errors.md +204 -208
- package/content/extensions/components/authorization/getting-started.md +227 -0
- package/content/extensions/components/authorization/index.md +88 -795
- package/content/extensions/components/authorization/usage.md +219 -528
- package/content/extensions/components/health-check.md +77 -243
- package/content/extensions/components/index.md +24 -90
- package/content/extensions/components/mail/api.md +553 -285
- package/content/extensions/components/mail/errors.md +76 -62
- package/content/extensions/components/mail/index.md +111 -463
- package/content/extensions/components/mail/usage.md +139 -173
- package/content/extensions/components/request-tracker.md +70 -173
- package/content/extensions/components/socket-io/api.md +462 -785
- package/content/extensions/components/socket-io/errors.md +49 -51
- package/content/extensions/components/socket-io/index.md +69 -372
- package/content/extensions/components/socket-io/usage.md +212 -105
- package/content/extensions/components/static-asset/api.md +461 -141
- package/content/extensions/components/static-asset/errors.md +121 -53
- package/content/extensions/components/static-asset/index.md +84 -606
- package/content/extensions/components/static-asset/usage.md +184 -299
- package/content/extensions/components/template/index.md +3 -3
- package/content/extensions/components/websocket/api.md +311 -404
- package/content/extensions/components/websocket/errors.md +47 -56
- package/content/extensions/components/websocket/index.md +75 -407
- package/content/extensions/components/websocket/usage.md +120 -338
- package/content/extensions/helpers/cron/index.md +52 -160
- package/content/extensions/helpers/crypto/index.md +67 -480
- package/content/extensions/helpers/crypto/reference.md +528 -0
- package/content/extensions/helpers/env/index.md +64 -178
- package/content/extensions/helpers/error/index.md +286 -196
- package/content/extensions/helpers/index.md +61 -47
- package/content/extensions/helpers/inversion/index.md +76 -550
- package/content/extensions/helpers/inversion/reference.md +530 -0
- package/content/extensions/helpers/kafka/admin.md +23 -3
- package/content/extensions/helpers/kafka/compile-binary.md +83 -52
- package/content/extensions/helpers/kafka/consumer.md +65 -28
- package/content/extensions/helpers/kafka/examples.md +46 -253
- package/content/extensions/helpers/kafka/index.md +55 -617
- package/content/extensions/helpers/kafka/producer.md +156 -22
- package/content/extensions/helpers/kafka/schema-registry.md +59 -79
- package/content/extensions/helpers/logger/hf-logger.md +220 -0
- package/content/extensions/helpers/logger/index.md +78 -552
- package/content/extensions/helpers/logger/pino.md +105 -0
- package/content/extensions/helpers/logger/reference.md +937 -0
- package/content/extensions/helpers/network/api.md +276 -195
- package/content/extensions/helpers/network/index.md +87 -524
- package/content/extensions/helpers/queue/index.md +80 -897
- package/content/extensions/helpers/queue/reference.md +494 -0
- package/content/extensions/helpers/redis/index.md +86 -640
- package/content/extensions/helpers/redis/reference.md +784 -0
- package/content/extensions/helpers/secrets/index.md +136 -0
- package/content/extensions/helpers/socket-io/api.md +325 -204
- package/content/extensions/helpers/socket-io/index.md +79 -429
- package/content/extensions/helpers/storage/api.md +584 -464
- package/content/extensions/helpers/storage/index.md +80 -573
- package/content/extensions/helpers/types/index.md +75 -495
- package/content/extensions/helpers/types/reference.md +689 -0
- package/content/extensions/helpers/uid/index.md +176 -189
- package/content/extensions/helpers/websocket/api.md +366 -214
- package/content/extensions/helpers/websocket/index.md +68 -503
- package/content/extensions/helpers/worker-thread/index.md +62 -396
- package/content/extensions/helpers/worker-thread/reference.md +428 -0
- package/content/extensions/index.md +38 -39
- package/content/extensions/src-details/mcp-server.md +96 -548
- package/content/guides/core-concepts/persistent/datasources.md +2 -2
- package/content/guides/core-concepts/persistent/index.md +5 -1
- package/content/guides/core-concepts/persistent/models.md +1 -1
- package/content/guides/core-concepts/persistent/pglite.md +218 -0
- package/content/guides/core-concepts/persistent/postgres-drivers.md +21 -15
- package/content/guides/core-concepts/persistent/search-meilisearch.md +22 -12
- package/content/guides/core-concepts/persistent/search-typesense.md +28 -16
- package/content/guides/core-concepts/persistent/sqlite.md +296 -0
- package/content/guides/core-concepts/persistent/transactions.md +12 -11
- package/content/guides/core-concepts/secrets-vault.md +177 -0
- package/content/guides/core-concepts/services.md +1 -1
- package/content/guides/get-started/5-minute-quickstart.md +59 -206
- package/content/guides/get-started/philosophy.md +135 -670
- package/content/guides/get-started/setup.md +53 -74
- package/content/guides/migrations/redis-helpers-migration.md +5 -4
- package/content/guides/migrations/scoped-rbac-migration.md +5 -5
- package/content/guides/migrations/unified-connectors-migration.md +8 -7
- package/content/guides/tutorials/ecommerce-api.md +3 -8
- package/content/guides/tutorials/realtime-chat.md +1 -1
- package/content/references/base/application.md +64 -22
- package/content/references/base/components.md +3 -3
- package/content/references/base/connectors.md +79 -136
- package/content/references/base/controllers.md +12 -12
- package/content/references/base/datasources-reference.md +600 -0
- package/content/references/base/datasources.md +84 -444
- package/content/references/base/dependency-injection.md +25 -46
- package/content/references/base/filter-system/application-usage.md +95 -123
- package/content/references/base/filter-system/array-operators.md +33 -43
- package/content/references/base/filter-system/comparison-operators.md +55 -63
- package/content/references/base/filter-system/default-filter.md +144 -350
- package/content/references/base/filter-system/fields-order-pagination.md +116 -148
- package/content/references/base/filter-system/index.md +114 -253
- package/content/references/base/filter-system/json-filtering.md +52 -181
- package/content/references/base/filter-system/list-operators.md +28 -44
- package/content/references/base/filter-system/logical-operators.md +69 -114
- package/content/references/base/filter-system/null-operators.md +41 -98
- package/content/references/base/filter-system/pattern-matching.md +48 -51
- package/content/references/base/filter-system/quick-reference.md +93 -196
- package/content/references/base/filter-system/range-operators.md +22 -38
- package/content/references/base/filter-system/tips.md +70 -133
- package/content/references/base/filter-system/use-cases.md +173 -232
- package/content/references/base/grpc-controllers.md +53 -17
- package/content/references/base/index.md +5 -3
- package/content/references/base/middlewares.md +43 -28
- package/content/references/base/models-reference.md +886 -0
- package/content/references/base/models.md +81 -1452
- package/content/references/base/providers.md +8 -8
- package/content/references/base/repositories/advanced.md +281 -419
- package/content/references/base/repositories/index.md +84 -644
- package/content/references/base/repositories/mixins.md +25 -21
- package/content/references/base/repositories/relations.md +194 -375
- package/content/references/base/repositories/soft-deletable.md +67 -55
- package/content/references/base/secrets.md +267 -0
- package/content/references/base/services.md +8 -6
- package/content/references/configuration/environment-variables.md +73 -21
- package/content/references/configuration/index.md +51 -31
- package/content/references/index.md +1 -1
- package/content/references/quick-reference.md +3 -16
- package/content/references/utilities/crypto.md +35 -76
- package/content/references/utilities/date.md +33 -73
- package/content/references/utilities/duration.md +85 -0
- package/content/references/utilities/index.md +6 -2
- package/content/references/utilities/jsx-reference.md +298 -0
- package/content/references/utilities/jsx.md +82 -525
- package/content/references/utilities/module.md +81 -61
- package/content/references/utilities/parse.md +34 -64
- package/content/references/utilities/performance.md +33 -58
- package/content/references/utilities/promise.md +28 -62
- package/content/references/utilities/request.md +58 -218
- package/content/references/utilities/retry.md +139 -0
- package/content/references/utilities/schema.md +43 -137
- package/content/references/utilities/statuses-reference.md +361 -0
- package/content/references/utilities/statuses.md +63 -667
- package/dist/mcp-server/index.js +0 -0
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/github/list-project-files.tool.js +3 -3
- package/dist/mcp-server/tools/github/search-code.tool.js +1 -1
- package/dist/mcp-server/tools/github/verify-dependencies.tool.js +1 -1
- package/dist/mcp-server/tools/github/view-source-file.tool.js +1 -1
- package/package.json +24 -23
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: HfLogger - High-Frequency Logging Guide
|
|
3
|
+
description: How to use the ring-buffer HfLogger correctly - setup, the ILogger surface, hot-path cost model, flusher lifecycle, and the limitations you must design around.
|
|
4
|
+
difficulty: advanced
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# HfLogger - High-Frequency Logging Guide
|
|
8
|
+
|
|
9
|
+
`HfLogger` is a fixed-layout ring-buffer logger for hot paths where even the standard `Logger` is too expensive. A log call writes a 256-byte binary entry into a lazily-allocated buffer. Nothing runs on the fast path: no string formatting, no transport I/O, no per-call allocation. A separate `HfLogFlusher` drains entries later, off the hot path.
|
|
10
|
+
|
|
11
|
+
It implements `ILogger` (`AbstractLogger`), so it's a drop-in replacement anywhere an `ILogger` is expected. Every level method works - `debug`, `info`, `warn`, `error`, `emerg`, plus `log` and `for`. But it stays entirely separate from the Winston-backed `Logger` pipeline: no formatters, no transports, no `APP_ENV_LOGGER_*` variables apply to it.
|
|
12
|
+
|
|
13
|
+
That separation buys enqueue speed - roughly 14x faster than pino on the same machine. See [Performance characteristics](#performance-characteristics) below for the measured numbers.
|
|
14
|
+
|
|
15
|
+
> [!IMPORTANT]
|
|
16
|
+
> Reach for `HfLogger` only when a profiler shows logging itself in your hot path - order engines, market-data ticks, per-packet paths at 100k+ events/sec. For everything else, the standard scoped `Logger` is the right tool: it formats, redacts, rotates files, and ships UDP. Most services never need this module.
|
|
17
|
+
|
|
18
|
+
## Mental model
|
|
19
|
+
|
|
20
|
+
One ring buffer per process holds 65,536 entries of 256 bytes each - 16MB total. It allocates lazily, on the first `HfLogger.get()` call, never at module import.
|
|
21
|
+
|
|
22
|
+
Writers stamp entries in. The ring never blocks and never grows.
|
|
23
|
+
|
|
24
|
+
When the ring is full, the next write overwrites the oldest entry. The buffer trades completeness for a bounded, allocation-free hot path. But every overwrite is counted and reported, never silent - see [Lap accounting](#lap-accounting) below.
|
|
25
|
+
|
|
26
|
+
**Entry layout (256 bytes):**
|
|
27
|
+
|
|
28
|
+
| Offset | Size | Field |
|
|
29
|
+
|--------|------|-------|
|
|
30
|
+
| 0-7 | 8 bytes | Timestamp (`float64` epoch milliseconds, sub-millisecond precision) |
|
|
31
|
+
| 8 | 1 byte | Level (`0`=debug, `1`=info, `2`=warn, `3`=error, `4`=emerg) |
|
|
32
|
+
| 9 | 1 byte | Scope length (0-32) |
|
|
33
|
+
| 10-41 | 32 bytes | Scope bytes |
|
|
34
|
+
| 42 | 1 byte | Message length (0-213) |
|
|
35
|
+
| 43-255 | 213 bytes | Message bytes |
|
|
36
|
+
|
|
37
|
+
The two length bytes are what make reads exact. The flusher decodes only the bytes a field actually holds, never the fixed-width remainder. So there's no NUL padding, no stale tail leaking from whatever a reused slot last held.
|
|
38
|
+
|
|
39
|
+
Because entries are fixed-width binary, everything you log must fit the layout above. Anything longer than the scope or message cap is truncated, not rejected.
|
|
40
|
+
|
|
41
|
+
## Setup - everything happens at initialization time
|
|
42
|
+
|
|
43
|
+
The hot path takes pre-encoded bytes, not strings. Encode once, at startup, and keep the references:
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
import { HfLogger, HfLogFlusher } from '@venizia/ignis-helpers';
|
|
47
|
+
|
|
48
|
+
// -- Initialization phase (once, before any hot path runs) --
|
|
49
|
+
|
|
50
|
+
// 1. Get the logger for a scope (cached; scope bytes are pre-computed)
|
|
51
|
+
const orderLogger = HfLogger.get('OrderEngine');
|
|
52
|
+
|
|
53
|
+
// 2. Pre-encode EVERY message the hot path will ever emit
|
|
54
|
+
const MSG_ORDER_SENT = HfLogger.encodeMessage('Order sent');
|
|
55
|
+
const MSG_ORDER_FILLED = HfLogger.encodeMessage('Order filled');
|
|
56
|
+
const MSG_ORDER_REJECTED = HfLogger.encodeMessage('Order rejected');
|
|
57
|
+
|
|
58
|
+
// 3. Start the background flusher
|
|
59
|
+
const flusher = new HfLogFlusher();
|
|
60
|
+
flusher.start(100); // drain every 100ms
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
// -- Hot path (bytes path, ~59ns/call) --
|
|
65
|
+
orderLogger.log('info', MSG_ORDER_SENT);
|
|
66
|
+
orderLogger.log('info', MSG_ORDER_FILLED);
|
|
67
|
+
orderLogger.log('error', MSG_ORDER_REJECTED);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// -- Or drain manually (for example, at a batch boundary or before shutdown) --
|
|
72
|
+
await flusher.flush();
|
|
73
|
+
|
|
74
|
+
// -- And stop the interval when the logger is no longer needed --
|
|
75
|
+
flusher.stop();
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## The ILogger surface - and its cost model
|
|
79
|
+
|
|
80
|
+
`HfLogger` implements the same `ILogger` methods as the standard `Logger`, so it can be typed and passed around as `ILogger`. But each method sits on a different point of the cost curve. Picking the right one is the whole point of this module:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { HfLogger } from '@venizia/ignis-helpers';
|
|
84
|
+
import type { ILogger } from '@venizia/ignis-helpers';
|
|
85
|
+
|
|
86
|
+
const logger: ILogger = HfLogger.get('OrderEngine');
|
|
87
|
+
|
|
88
|
+
// Fast: no-args string call resolves through the same bounded encode cache as
|
|
89
|
+
// encodeMessage() - a Map.get() plus the bytes-path write. ~66ns/call on a cache hit.
|
|
90
|
+
logger.info('Order sent');
|
|
91
|
+
|
|
92
|
+
// Slow path: any args force formatLogMessage() (deep inspection + secret redaction)
|
|
93
|
+
// and an UNCACHED encode, because dynamic strings must never grow the cache.
|
|
94
|
+
// Correct, but this is not the hot path - use it for control-flow events, not per-tick data.
|
|
95
|
+
logger.info('Order sent: %s', orderId);
|
|
96
|
+
|
|
97
|
+
// debug() returns before any encoding when SHOULD_LOG_DEBUG is false (same gate as Logger).
|
|
98
|
+
logger.debug('Verbose diagnostic');
|
|
99
|
+
|
|
100
|
+
// .for() composes a sub-scope the same way BaseLogger does.
|
|
101
|
+
const fillLogger = logger.for('fill');
|
|
102
|
+
fillLogger.info('Order filled');
|
|
103
|
+
|
|
104
|
+
// log() also accepts pre-encoded bytes directly - the true hot path, unchanged from before.
|
|
105
|
+
const MSG_ORDER_SENT = HfLogger.encodeMessage('Order sent');
|
|
106
|
+
logger.log('info', MSG_ORDER_SENT);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Rule of thumb:
|
|
110
|
+
|
|
111
|
+
| When | Use | Cost |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| A per-event, per-tick, per-packet path | Pre-encode, then call the bytes overload | ~59ns/op |
|
|
114
|
+
| A small fixed set of facts you didn't pre-encode | The no-args string call | ~66ns/op |
|
|
115
|
+
| Off the true hot path only | The args form (dynamic `%s` data) | Correct - nothing is ever silently dropped - but not free |
|
|
116
|
+
|
|
117
|
+
## The rules that keep it fast and correct
|
|
118
|
+
|
|
119
|
+
**1. Never encode in the hot path.** `HfLogger.encodeMessage` remembers every distinct string it sees. So does the no-args string call, since it shares the same cache. That cache is FIFO-bounded at 4096 entries.
|
|
120
|
+
|
|
121
|
+
Calling it with dynamic strings (`encodeMessage('order ' + id)`) still puts UTF-8 encoding on your hot path. Worse, it evicts the oldest cached message once you cross the cap - corrupting the fixed vocabulary you rely on elsewhere.
|
|
122
|
+
|
|
123
|
+
If a value varies per event, it doesn't belong in an `HfLogger` message. Log the static fact here, and the variable detail through the standard `Logger` at a lower frequency. Or use the args form, off the hot path.
|
|
124
|
+
|
|
125
|
+
**2. A fixed vocabulary of messages.** The bytes path targets a finite set of pre-encoded facts: "Order sent", "Tick received", "Risk check failed".
|
|
126
|
+
|
|
127
|
+
If you find yourself needing free-form text on the hot path, you're in the wrong module. Use the args form instead, off the hot path.
|
|
128
|
+
|
|
129
|
+
**3. Size the flush interval against your write rate.** The ring holds 65,536 entries. Write more than that between two flushes, and the oldest unflushed entries get overwritten. The flusher reports exactly how many via `dropped` on the sink batch - never silently (see below).
|
|
130
|
+
|
|
131
|
+
Pick the interval so `writeRate x interval < 65,536`, with comfortable margin. At 100k logs/sec, a 100ms interval accumulates ~10k entries per drain - safe. At 1M logs/sec, you need ~30ms or faster.
|
|
132
|
+
|
|
133
|
+
**4. One process, one thread.** `HfLogger` is safe only on a single thread within a single process. The write index is a plain counter - not shared, not atomic.
|
|
134
|
+
|
|
135
|
+
Don't log to it from worker threads. Each worker that imports the module gets its own independent ring, and nothing coordinates them. This is a documented design point, not an accident.
|
|
136
|
+
|
|
137
|
+
**5. Flush before shutdown.** Entries live only in memory. An exiting process loses everything not yet flushed. Call `await flusher.flush()` in your shutdown path, and `flusher.stop()` to clear the interval.
|
|
138
|
+
|
|
139
|
+
## The flusher
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
import { HfLogFlusher } from '@venizia/ignis-helpers';
|
|
143
|
+
import type { IHfLogFlusherOptions } from '@venizia/ignis-helpers';
|
|
144
|
+
|
|
145
|
+
// Default: renders to stdout, one write() per batch of up to 1024 entries.
|
|
146
|
+
const flusher = new HfLogFlusher();
|
|
147
|
+
|
|
148
|
+
// Append to a file instead of stdout.
|
|
149
|
+
const fileFlusher = new HfLogFlusher({ filePath: './app_data/hf.log' });
|
|
150
|
+
|
|
151
|
+
// Full custom delivery - receives the rendered lines AND the drop count for this batch.
|
|
152
|
+
const customFlusher = new HfLogFlusher({
|
|
153
|
+
sink: batch => {
|
|
154
|
+
if (batch.dropped > 0) {
|
|
155
|
+
console.warn(`HfLogFlusher lapped: ${batch.dropped} entries overwritten`);
|
|
156
|
+
}
|
|
157
|
+
shipToAggregator(batch.lines);
|
|
158
|
+
},
|
|
159
|
+
batchSize: 512,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
flusher.start(100); // interval-based draining, unref'd so it never blocks process exit
|
|
163
|
+
await flusher.flush(); // one-shot drain, for example before shutdown
|
|
164
|
+
flusher.stop(); // clears the interval; start() again to resume
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
A rendered line looks like this:
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
2026-07-18T09:41:03.128Z [info] OrderEngine Order sent
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
`<ISO timestamp> [<level name>] <scope> <message>` - readable, parseable, and free of NULs or stale bytes.
|
|
174
|
+
|
|
175
|
+
### Lap accounting
|
|
176
|
+
|
|
177
|
+
Every batch the flusher hands to its sink carries `dropped: number`. That's the count of entries the ring overwrote before the flusher could read them, since the previous batch. The default sink emits a `warn` marker line ahead of the batch when `dropped > 0`:
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
2026-07-18T09:41:03.200Z [warn] HfLogFlusher ring lapped - 342 entries overwritten before they could be read
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
A custom `sink` gets the same `dropped` count on `batch.dropped` and decides how to surface it. This replaces the old silent behavior, where a lapped ring emitted whatever currently sat in each slot with no warning.
|
|
184
|
+
|
|
185
|
+
## Current limitations
|
|
186
|
+
|
|
187
|
+
These are real behaviors of the current implementation - design around them:
|
|
188
|
+
|
|
189
|
+
- **Single-thread only.** The write index is not shared or atomic across threads. Each worker thread that imports the module gets an independent ring. Don't log to `HfLogger` from worker threads expecting a shared buffer.
|
|
190
|
+
- **The ring overwrites the oldest entry when lapped.** If the producer writes faster than the flusher drains (see rule 3 above), unflushed entries get silently overwritten in memory.
|
|
191
|
+
- **The loss is visible, not invisible.** The flusher counts and reports every overwritten entry via `dropped`.
|
|
192
|
+
- **213-byte message cap, 32-byte scope cap.** Both are truncation-only - a longer value is cut, not rejected.
|
|
193
|
+
- **Truncation happens at a byte boundary, not a character boundary.** It can split a multibyte UTF-8 character - the truncated tail then renders as the U+FFFD replacement character.
|
|
194
|
+
- **Run one flusher per process.** Each `HfLogFlusher` tracks its own read position from the start of the ring - not a shared cursor. A second flusher re-emits entries the first one already drained.
|
|
195
|
+
- **A fixed, pre-encoded vocabulary is still the right pattern for the bytes path.** `HfLogger.encodeMessage` and the no-args string call exist to make the ENCODE cost a one-time expense.
|
|
196
|
+
- **The args form is correct, but it's the slow path by design.** Reserve it for control-flow events, off the hot path.
|
|
197
|
+
- **The encode cache is FIFO-bounded at 4096 entries.** That's well within a real fixed vocabulary. But a hot path that generates many distinct dynamic strings, through the no-args string call, will start evicting and re-encoding.
|
|
198
|
+
|
|
199
|
+
## Performance characteristics
|
|
200
|
+
|
|
201
|
+
Measured on Bun 1.3.14, 1M-iteration median:
|
|
202
|
+
|
|
203
|
+
| Path | Cost | Notes |
|
|
204
|
+
|------|------|-------|
|
|
205
|
+
| Bytes (`log(level, preEncodedBytes)`) | 59.4ns/op | The true hot path - no formatting, no allocation |
|
|
206
|
+
| String, no args (`info('Order sent')`) | 66.0ns/op | Cache-hit encode lookup + bytes-path write |
|
|
207
|
+
| pino, sync, `/dev/null` | 831ns/op | ~14x slower than the `HfLogger` bytes path on the same machine |
|
|
208
|
+
|
|
209
|
+
Heap growth measured at 0.0MB over 1M bytes-path logs - the hot path does not allocate. That buys an ENQUEUE, not a durable log line. The flusher still pays rendering cost later, off the hot path.
|
|
210
|
+
|
|
211
|
+
## See also
|
|
212
|
+
|
|
213
|
+
- [Logger overview](/extensions/helpers/logger/) - the standard scoped logger (start here)
|
|
214
|
+
- [Full reference](/extensions/helpers/logger/reference) - `HfLogger`/`HfLogFlusher` API tables and the ring-buffer entry format
|
|
215
|
+
- [Performance best practices](/best-practices/performance-optimization) - when high-frequency logging is and is not the answer
|
|
216
|
+
|
|
217
|
+
**Files:**
|
|
218
|
+
|
|
219
|
+
- [`packages/helpers/src/modules/logger/hf/logger.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/hf/logger.ts) - `HfLogger`
|
|
220
|
+
- [`packages/helpers/src/modules/logger/hf/flusher.ts`](https://github.com/VENIZIA-AI/ignis/blob/main/packages/helpers/src/modules/logger/hf/flusher.ts) - `HfLogFlusher`
|