@algoraid/logger
v0.3.0
Published
Remote logger for Node, Next.js, and Nest.js apps. Captures all stdout/stderr (incl. NestJS Logger) by default. Posts to your Algora dashboard.
Downloads
109
Maintainers
Readme
@algoraid/logger
Remote logger for Node, Next.js, and Nest.js apps. Posts log entries to your Algora dashboard at https://dashboard.algora.id/api/logs/ingest (or any custom endpoint).
- 5 levels:
debug/info/warn/error/fatal - Free-text body, optional structured
contextJSON, optionalsourceandenvironment - Captures all stdout/stderr by default —
console.*, the NestJSLogger/ConsoleLogger(which bypassesconsole.*), Next.js server output, pino, rawprocess.stdout.write, … with no code changes to your app - Non-blocking transport — batched, in-memory queue (default 200),
fetch(keepalive: true), 2s abort timeout. Never throws into the host app.
Install
npm install @algoraid/loggerSetup
Get an App ID and Secret from your Algora dashboard's /logs page (Manage → New app). Set them as env vars:
ALGORA_LOG_APP_ID=app_…
ALGORA_LOG_SECRET=…Node / generic
import { init, log, shutdown } from '@algoraid/logger'
init({
appId: process.env.ALGORA_LOG_APP_ID!,
secret: process.env.ALGORA_LOG_SECRET!,
environment: process.env.NODE_ENV,
})
log.info('cron started', { source: 'cron/nightly' })
log.warn({ msg: 'queue depth high', depth: 1234 })
log.error(new Error('database timeout'))
// On shutdown: flush remaining queue
process.on('SIGTERM', async () => {
await shutdown()
process.exit(0)
})Next.js
In your app's instrumentation.ts:
import { init } from '@algoraid/logger'
export { onRequestError } from '@algoraid/logger/next'
export function register() {
init({
appId: process.env.ALGORA_LOG_APP_ID!,
secret: process.env.ALGORA_LOG_SECRET!,
environment: process.env.NODE_ENV,
})
}Wrap server actions so thrown errors are captured before they bubble:
'use server'
import { withLogging } from '@algoraid/logger/next'
export const updateUser = withLogging('updateUser', async (input) => {
// …throw inside here → automatically logged as level=error, source="updateUser"
})Or call directly:
import { log, captureError } from '@algoraid/logger'
log.info('user signed in', { context: { userId } })
try { … } catch (err) { captureError(err, { source: 'POST /api/users' }) }Nest.js
In your AppModule:
import { Module } from '@nestjs/common'
import { LoggerModule } from '@algoraid/logger/nest'
@Module({
imports: [
LoggerModule.forRoot({
appId: process.env.ALGORA_LOG_APP_ID!,
secret: process.env.ALGORA_LOG_SECRET!,
environment: process.env.NODE_ENV,
}),
],
})
export class AppModule {}Every thrown error (HTTP or generic) in any controller is captured automatically. Plus, every line the NestJS Logger/ConsoleLogger prints — framework boot logs (RouterExplorer, RoutesResolver, …) and your own new Logger('Foo').error(...) calls — is forwarded too, because capture works at the stdout/stderr level and NestJS writes there directly (it never goes through console.*). To also catch the earliest boot lines, call init() at the very top of main.ts before NestFactory.create. Use log.* for explicit entries:
import { log } from '@algoraid/logger'
@Controller('orders')
export class OrdersController {
@Post()
create(@Body() body: CreateOrderDto) {
log.info('order created', { source: 'POST /orders', context: { id: body.id } })
}
}Log capture (stdout/stderr, on by default)
Once init() has run, everything written to stdout/stderr is forwarded to the dashboard — in addition to its normal terminal output. On Node this wraps process.stdout.write / process.stderr.write, so it catches it all:
console.log/.info/.warn/.error/.debug- the NestJS
Logger/ConsoleLogger, which writes straight to the streams and never callsconsole.*(this is exactly why earlier versions missed framework +Loggeroutput) - Next.js server output, pino, winston, raw
process.stdout.write, …
You don't have to rewrite any existing code to start seeing logs.
Level is read from the line when possible: structured loggers (NestJS, pino, winston) print an UPPERCASE level token near the start — ERROR, WARN, LOG/INFO, DEBUG/VERBOSE, FATAL — which is matched and mapped. Otherwise it falls back to the stream: stderr → error, stdout → info.
Entries are tagged with source: "stdout" or "stderr". ANSI colour codes are stripped from the forwarded body (your terminal still shows colour). Multi-line output (stack traces, pretty-printed JSON bodies) is kept together as a single entry.
On runtimes without real stdio (Next.js Edge, browser) capture falls back to patching
console.*directly —source: "console", with per-method levels (console.warn→warn,console.error→error, etc.).
Opting out
init({
appId: …,
secret: …,
captureConsole: false,
})Silencing noisy lines
Captured calls are matched against the optional consoleIgnore regex list. Matches still print to stdout/stderr but are not forwarded.
init({
appId: …,
secret: …,
consoleIgnore: [
/^\[next\]/, // Next.js compile noise
/\[(RouterExplorer|RoutesResolver|InstanceLoader|NestFactory)\]/, // NestJS boot spam
/Prisma:Query/, // Prisma slow-query logs
/DeprecationWarning/, // Node deprecation spam
],
})Dev-mode caveat
Next.js dev + Turbopack and NestJS startup are extremely chatty — and because capture now includes the framework's own stdout (every RouterExplorer / RoutesResolver boot line), there's more of it than before. With the default maxQueue: 200, batchSize: 50, and the dashboard's per-app rate limit (100 entries/sec sustained, 500 burst), a single dev refresh or a cold boot can cause batches to drop or 429. In development you'll usually want either captureConsole: false or a generous consoleIgnore list (see the NestJS boot patterns above). Default-on is intended for production.
Config
| Option | Default | What |
|---|---|---|
| appId | required | From dashboard |
| secret | required | From dashboard |
| endpoint | https://dashboard.algora.id/api/logs/ingest | Override for self-hosted |
| environment | — | 'production' / 'staging' / etc. |
| source | — | Default source for entries that don't override |
| maxQueue | 200 | Max buffered entries before oldest is dropped |
| batchSize | 50 | Entries per network call |
| flushIntervalMs | 1000 | Periodic flush even if batch isn't full |
| captureConsole | true | Forward all stdout/stderr (console.*, NestJS Logger, …) to the dashboard. Name kept for back-compat; set false to opt out |
| consoleIgnore | [] | Regexes — matching lines still print to stdout/stderr but aren't forwarded |
Notes
- Bodies > 16 KB are server-truncated.
- Up to 100 entries per ingest request; the SDK batches automatically.
- Per-app rate limit: 100 entries/sec sustained, 500 burst. Excess returns 429.
- Logs in flight when the host process exits are lost unless you call
await shutdown(). shutdown()also restores the originalconsole.*methods, so test isolation and re-init cycles are clean.
License
MIT
