Enhancing iTwin.js Logging with Bunyan and Seq for Better Observability
Effective logging is crucial for monitoring and debugging modern applications. In iTwin.js applications, leveraging structured logging can…
Enhancing iTwin.js Logging with Bunyan and Seq for Better Observability
Effective logging is crucial for monitoring and debugging modern applications. In iTwin.js applications, leveraging structured logging can significantly improve the observability of backend services. This blog explores how to integrate Bunyan and Seq with iTwin.js — the library for developing infrastructure digital twin applications — to establish a efficient logging mechanism.

Seq integration with iTwin.js
Why Use Bunyan and Seq?
Bunyan is a high-performance, JSON-based logger for Node.js that provides structured logs. Seq is a structured logging server that allows real-time search and analysis of logs with a rich query interface. Integrating these tools enhances log management by enabling structured logging with minimal performance overhead.
Here are the steps to implement logging in an iTwin.js application using Bunyan and Seq.
1. Setup Seq and Project
- Download, Install and run Seq. For more details, refer to the Seq Getting Started documentation.
- Setup a Node.js project or copy it from here: iTwinjsStarterKit Node Template
2. Install Dependencies
To get started, install the required dependencies:
npm install bunyan bunyan-seq @itwin/core-bentley dotenv
npm install --save-dev @types/bunyan
3. Configure Logging
Create a Logger.config.json file with the following content to define log levels:
{
"loggerConfig": {
"defaultLevel": "${LOG_LEVEL}",
"categoryLevels": [
{"category": "Logging.SeqIntegrated", "logLevel": "Trace"}
]
}
}
Create a BackendLogger.ts file to initialize logging:
import { Logger, LoggerLevelsConfig } from "@itwin/core-bentley";
import bunyan from "bunyan";
import seq from "bunyan-seq";
import config from "./Logger.config.json";
/**
* Creates and configures the Bunyan logger.
*/
function createBunyanLogger(): bunyan {
return bunyan.createLogger({
name: process.env.APP_NAME || "SeqLogger",
streams: [
{
stream: process.stdout,
level: process.env.LOG_LEVEL?.toLowerCase() as bunyan.LogLevel || "error",
},
seq.createStream({
serverUrl: process.env.SEQ_URL || "http://127.0.0.1:5341",
apiKey: process.env.SEQ_API_KEY || "",
level: process.env.LOG_LEVEL?.toLowerCase() as bunyan.LogLevel || "error"
})
]
});
}
/**
* Initializes logging for the application.
*/
export function initializeLogging(logLevel: string = "Error"): void {
const bunyanLogger = createBunyanLogger();
const bunyanLogFunction = (category: string, message: string, meta: any, level: string) => {
switch (level.toLowerCase()) {
case "error":
bunyanLogger.error({ category, ...meta }, message);
break;
case "warn":
bunyanLogger.warn({ category, ...meta }, message);
break;
case "info":
bunyanLogger.info({ category, ...meta }, message);
break;
case "trace":
bunyanLogger.trace({ category, ...meta }, message);
break;
default:
bunyanLogger.info({ category, ...meta }, message);
break;
}
};
/*
Note: The initialize will set the default log level to undefined and category to empty
Its important to set the default log level and configure after calling initialize
*/
Logger.initialize(
(category, message, meta) => bunyanLogFunction(category, message, meta, "error"),
(category, message, meta) => bunyanLogFunction(category, message, meta, "warn"),
(category, message, meta) => bunyanLogFunction(category, message, meta, "info"),
(category, message, meta) => bunyanLogFunction(category, message, meta, "trace")
);
if ("loggerConfig" in config) {
config.loggerConfig.defaultLevel = logLevel;
Logger.validateProps(config.loggerConfig);
Logger.configureLevels(config.loggerConfig as LoggerLevelsConfig);
}
}
Note: The Logger initialize will set the default log level to undefined and category to empty. Its important to set the default log level and configure after calling initialize.
4. Initialize Logging
Create/Modify index.ts file to load environment variables and initialize logging:
import { Logger } from "@itwin/core-bentley";
import * as dotenv from "dotenv";
import { initializeLogging } from "./BackendLogger";
// Load environment variables from .env file
dotenv.config();
/**
* Main function initializing logging
* @async
* @function main
* @returns {Promise<void>}
*/
(() => {
initializeLogging(process.env.LOG_LEVEL);
Logger.logError("Logging.SeqIntegrated", "Logging Seq Error");
Logger.logWarning("Logging.SeqIntegrated", "Logging Seq Warning");
Logger.logInfo("Logging.SeqIntegrated", "Logging Seq Info");
Logger.logTrace("Logging.SeqIntegrated", "Logging Seq Trace");
})();
5. Define Environment Variables
Create/update .env file to specify logging configurations:
APP_NAME=SeqIntegratedLogger
LOG_LEVEL=Trace
SEQ_URL=http://127.0.0.1:5341
SEQ_API_KEY=your-seq-api-key
You can generate SEQ_API_KEY from Seq admin API keys.
6. Build and Run the application
Build and run the application
npm run build
npm run start
Now, you should be able to find the logs in Seq.

Seq Logs
Conclusion
By integrating Bunyan and Seq with iTwin.js, you can achieve powerful, structured logging for your backend services. This setup not only enhances debugging but also provides deep insights into application performance. For a full working example, visit the GitHub repository: SeqIntegrated Logging Sample.
Try implementing this in your iTwin.js project and take your logging capabilities to the next level!
메타데이터
- post_id
- bc0f54db9707
- slug
- enhancing-itwin-js-logging-with-bunyan-and-seq-for-better-observability-bc0f54db9707
- url
- https://medium.com/@asad_bukhari/enhancing-itwin-js-logging-with-bunyan-and-seq-for-better-observability-bc0f54db9707
- canonical_url
- https://medium.com/@asad_bukhari/enhancing-itwin-js-logging-with-bunyan-and-seq-for-better-observability-bc0f54db9707
- author_url
- https://medium.com/@asad_bukhari
- status
- ok
- fetched_at
- 2026-06-26 06:47:43