Node.js
Log from servers, workers and scripts, and capture crashes yourself.
What is different on a server
- Nothing is captured automatically: no errors, requests or timings. You log what you need.
- The SDK adds the platform and Node.js version to every log’s context.
- It registers handlers for
SIGINTandSIGTERMthat send the last logs and exit. See below.
The SDK uses the global fetch, so it needs Node.js 18 or later. Install it with npm install apperio; both import and require work.
1. Create the logger
import { Apperio } from 'apperio';
export const logger = new Apperio({
apiKey: process.env.APPERIO_API_KEY ?? '',
projectId: process.env.APPERIO_PROJECT_ID ?? '',
environment: process.env.NODE_ENV ?? 'development',
serviceName: 'api',
});The constructor throws if either value is empty, so a missing environment variable stops the process at startup rather than losing logs quietly.
2. Capture crashes
import { logger } from './apperio';
process.on('uncaughtException', (error) => {
logger.fatal('Uncaught exception', error);
void logger.flush().finally(() => process.exit(1));
});
process.on('unhandledRejection', (reason) => {
const error = reason instanceof Error ? reason : new Error(String(reason));
logger.error('Unhandled rejection', error);
});After an uncaught exception the process is in an unknown state, so this exits once the report is sent. Each error becomes an issue in Apperio, grouped by its name, message and stack.
3. Log what matters
Log failures with the error, and important events with enough data to find them later:
export async function handleRefund(orderId: string) {
try {
await processOrder(orderId);
logger.info('Refund issued', { orderId });
} catch (err) {
const error = err instanceof Error ? err : new Error(String(err));
logger.error('Refund failed', error, { orderId });
throw error;
}
}In a web framework, log errors from its error handler, the one place every failed request passes through.
Scripts and jobs
The logger’s flush timer keeps Node.js running. At the end of a script, shut it down so the last logs go out and the process can exit:
import { logger } from '../src/apperio';
try {
await runJob();
logger.info('Nightly job finished');
} catch (err) {
logger.error('Nightly job failed', err instanceof Error ? err : new Error(String(err)));
process.exitCode = 1;
} finally {
await logger.shutdown();
}SIGTERM and SIGINT
On either signal, the SDK’s handler calls logger.shutdown() and then process.exit(0).
Graceful shutdowns