node-app-logger

skill

How to add and use @ivannikov-pro/app-logger — log4js-based logging with convict integration. Use when adding logging to a package.

v1.0.0development
logginglog4jsconvictnodeobservability
Install this skill
$npx @ivannikov-pro/ai-agent-kit@latest add node-app-logger

Using app-logger

@ivannikov-pro/app-logger — log4js-based logging with convict schema integration. Supports stdout, stderr, date-rolling file, and GELF appenders.

Source: packages/app-logger (monorepo local) Version: 1.0.0 · Skill updated: 2026-03-21

When to Use

  • Adding @ivannikov-pro/app-logger to a new package or app
  • Configuring logger appenders (stdout, file, GELF)
  • Setting up logger schema integration with app-config

When NOT to Use

  • Configuring log4js directly without the wrapper (use node-log4js skill)
  • Working with config schemas only (use node-app-config skill)

Prerequisites

Requires @ivannikov-pro/app-config as a peer dependency. Your config schema must include dataConfigSchema (for file appender paths).

Setup (2 files)

1. Add logger schema to your config (in config/schema.ts):

import {
  envConfigSchema,
  type EnvConfig,
  dataConfigSchema,
  type DataConfig,
  fileConfigSchema,
  type FileConfig,
} from "@ivannikov-pro/app-config";
import { loggerConfigSchema, type LoggerConfig } from "@ivannikov-pro/app-logger";

const mySchema = {
  /* your custom schema */
};
type MyConfig = {
  /* your custom type */
};

export const schema = {
  ...envConfigSchema,
  ...dataConfigSchema,
  ...fileConfigSchema,
  ...loggerConfigSchema, // adds logger.* config fields
  ...mySchema,
};

export type ConfigSchema = EnvConfig & DataConfig & FileConfig & LoggerConfig & MyConfig;

2. Create logger.ts at src root:

import { initLogger } from "@ivannikov-pro/app-logger";
import config from "./config";

export default initLogger(config);
export const loggerPrefix = "MyApp";

3. Use it anywhere:

import log4js, { loggerPrefix } from "./logger";
const logger = log4js.getLogger(`${loggerPrefix}:module-name`);

logger.info("Server started");
logger.error("Something failed", err);
logger.debug("Debugging info", { key: "value" });

package.json dependency

{
  "dependencies": {
    "@ivannikov-pro/app-config": "workspace:*",
    "@ivannikov-pro/app-logger": "workspace:*"
  }
}

Environment Variables

Env varDefaultDescription
LOGGER_LEVELinfoLog level: fatal, error, warn, info, debug, trace
LOGGER_STDOUTtrueEnable stdout appender
LOGGER_STDERRfalseEnable stderr appender
LOGGER_FILEfalseEnable date-rolling file appender
LOGGER_GELFfalseEnable GELF (Graylog) appender
LOGGER_PM2falseEnable PM2 clustering
LOGGER_FILE_NAMEdebug.logLog file name (in data.dir)
LOGGER_GELF_HOST127.0.0.1GELF server host
LOGGER_GELF_PORT12201GELF server port

Key Types

import type { Logger, Log4js } from "@ivannikov-pro/app-logger";
import type { LoggerConfig, LoggerConfigExtra, ConfigLogger } from "@ivannikov-pro/app-logger";
TypeUse for
LoggerIndividual logger instance (log4js.getLogger() return)
Log4jsThe log4js module instance
LoggerConfigSchema type for logger.* fields only
LoggerConfigExtraLoggerConfig & DataConfig & EnvConfig
ConfigLoggerConfig<LoggerConfigExtra> — for function params

⚠️ Gotchas

TS2589 with config.has()

// @ts-ignore — convict Path<any> causes deep type instantiation in dts builds
if (!config.has("logger") || !config.has("data")) { ... }

File appender needs data.dir

The file appender writes to join(config.get("data.dir"), config.get("logger.file.name")). Your config schema must include dataConfigSchema.

Import from app-config

Types like Config, DataConfig, EnvConfig must come from @ivannikov-pro/app-config, not from convict directly.