--- url: 'https://medicus.js.org/todo.md' --- # 🚧 Oops! This page you are looking for is under development and is not ready yet. Please check back later. Wanna help? Feel free to contribute to this page by [submitting a pull request](https://github.com/arthurfiorette/medicus). 🙏 --- --- url: 'https://medicus.js.org/integrations/avvio.md' --- # Avvio Avvio is a highly performant application booting and plugin system, designed to manage the loading and bootstrapping of asynchronous components in Node applications. It's the core plugin system used by Fastify and other frameworks, providing a reliable and type-safe way to handle plugin registration and dependencies. The `avvioMedicusPlugin` integrates Medicus health checking capabilities into your Avvio-based application, allowing you to monitor the health of your services while taking advantage of Avvio's plugin system. It automatically registers a Medicus instance within your application context and handles proper cleanup on application shutdown. ## Options The `avvioMedicusPlugin` accepts the following options: * **`plugins`**: Array of Medicus plugins to register (e.g., [`nodeMedicusPlugin`](/integrations/node), [`pinoMedicusPlugin`](/integrations/pino)). * **`checkers`**: Object containing health check functions for different services. * **`backgroundCheckInterval`**: Interval in milliseconds for background health checks (set to a number greater than 0 to enable, defaults to undefined). * **`onBackgroundCheck`**: Callback function executed after each background health check. ## Example of usage The plugin enables automated health monitoring through background checks and heartbeat reporting. This feature is crucial for maintaining service reliability by continuously verifying your system's health and reporting its status to external systems. Here's an example of heartbeat reporting: ```ts import avvio from 'avvio' import { HealthStatus } from 'medicus' import { avvioMedicusPlugin, AvvioMedicus } from 'medicus/avvio.js' import { nodeMedicusPlugin } from 'medicus/node.js' import { pinoMedicusPlugin } from 'medicus/pino.js' type Context = { medicus: AvvioMedicus; }; // medicus is added later by the plugin const app = avvio({} as Context); app.use(avvioMedicusPlugin({ checkers: { database() { return HealthStatus.HEALTHY } }, backgroundCheckInterval: 30_000, // 30s async onBackgroundCheck(checkResult) { if (checkResult.status !== HealthStatus.HEALTHY) { console.error('Background check failed', checkResult) return } // Sending heartbeat to a external system await fetch(process.env.HEARTBEAT_URL!) } })); ``` --- --- url: 'https://medicus.js.org/background-checks.md' --- # Background Checks In some cases, you might not want to manually trigger checks with every `performCheck` call. Instead, you may prefer to run checks on a consistent schedule. This is where **background checks** come into play. ## Setting Up Background Checks You can configure Medicus to automatically run checks at a specified interval. By setting the `backgroundCheckInterval` option, you can ensure a consistent schedule for performing health checks without needing to call `performCheck` manually. ```ts import { Medicus } from 'medicus'; const medicus = new Medicus({ // Automatically calls performCheck every 60 seconds backgroundCheckInterval: 60_000 }); ``` After setting up the background check interval, you can retrieve the result of the last performed check using `getLastCheck()`. If the check has never been run, it will return `null`. ```ts const check = medicus.getLastCheck(true); // Prints `null` if the check has never been run // or the details of the last check console.log(check); ``` With background checks enabled, Medicus will automatically run health checks on a consistent interval, but you can still manually trigger a check whenever necessary using `performCheck()`. ## Immediate Execution with `eagerBackgroundCheck` When you enable background checks, you can control whether an initial health check runs immediately upon initialization or if Medicus should wait for the first interval to elapse. This behavior is controlled by the eagerBackgroundCheck option, which defaults to true. This is especially useful to avoid unintentionally flagging containers with downtime when during deployment of new versions, since it would restart the timeout once the container starts back up again, delaying the first health report. ```ts import { Medicus } from 'medicus'; const medicus = new Medicus({ backgroundCheckInterval: 60_000, // Controls whether a health check runs immediately eagerBackgroundCheck: false }); ``` ## Listening for Background Checks You can also set up an event listener to monitor when a background check is performed. The listener can be either `sync` or `async` and will be triggered every time a check is completed. ```ts import { Medicus } from 'medicus'; const medicus = new Medicus({ backgroundCheckInterval: 60_000, onBackgroundCheck(check) { console.log('Background check performed', check); } }); ``` The above example will log the check object every time a background check is performed, i.e., every 60 seconds. If an error is thrown inside the event listener, it will be captured and sent to the [`errorLogger`](./error-logger.md), if one has been configured. ## `setTimeout` vs `setInterval` Under the hood the `medicus` uses the `setTimeout` method to perform its pooled background checks. The choice is based on the fact that we do not want to add additional pressure to the system. In fact, it is known that `setInterval` will call repeatedly at the scheduled time regardless of whether the previous call ended or not, and if the server is already under load, this will likely increase the problem, because those `setInterval` calls will start piling up. `setTimeout`, on the other hand, is called only once and does not cause the mentioned problem. One note to consider is that because the two methods are not identical, the timer function is not guaranteed to run at exactly the same rate when the system is under pressure or running a long-running process. --- --- url: 'https://medicus.js.org/checkers.md' --- # Checkers A **Checker** is a function responsible for assessing the health of a specific sub-service or component within your application. These functions can be either `async` or `sync` and must return one of the following: * `void` (no value returned) * An `Error` (to signal failure) * A value from the `HealthStatus` enum * A `DetailedHealthCheck` (for a more detailed response) ## Throwing Errors To indicate that a service is unhealthy, you can throw an error inside your checker function. This method only signals failure (unhealthy state) and does not support the `DEGRADED` status. ```ts medicus.addChecker({ // Async support is optional service(ctx) { if (ctx.hasError) { // This error will be logged via the errorLogger throw ctx.error; } } }); ``` ## Using `HealthStatus` For simpler health status checks, you can directly return a value from the `HealthStatus` enum. ```ts import { HealthStatus } from 'medicus'; medicus.addChecker({ service(ctx) { if (ctx.hasError) { return HealthStatus.UNHEALTHY; } if (ctx.isBusy) { return HealthStatus.DEGRADED; } return HealthStatus.HEALTHY; } }); ``` ## Detailed Result When using the [debug view](./debug-view.md), you can return more detailed information alongside the health status. This is particularly helpful when you want to provide additional context, such as messages, version information, or any other relevant data for debugging. ```ts import { HealthStatus } from 'medicus'; medicus.addChecker({ service(ctx) { return { status: HealthStatus.HEALTHY, debug: { message: 'Everything is fine', foo: 'bar', version: ctx.serviceVersion } }; } }); ``` When calling `await medicus.performCheck(true)` with debugging enabled, you'll receive the following output: ```json { "status": "healthy", "services": { "service": { "status": "healthy", "debug": { "message": "Everything is fine", "foo": "bar", "version": "1.0.0" } } } } ``` --- --- url: 'https://medicus.js.org/debug-view.md' --- # Debug View Medicus allows you to include detailed debugging information for health checkers that return [detailed results](./checkers.md#detailed-result). By default, this debugging data is not included in the check results, but you can enable it by setting the `debug` option to `true`. This is particularly useful for troubleshooting or gathering additional insights into why a service or checker is reporting a particular status. ```ts import { Medicus, HealthStatus } from 'medicus'; const medicus = new Medicus({ checkers: { service() { return { status: HealthStatus.HEALTHY, debug: { foo: 'bar' } }; } } }); ``` ### With Debugging Enabled When debugging is enabled (via `true`), the resulting check output will include the debug information returned by each checker. ```ts await medicus.performCheck(true); const result = { status: 'HEALTHY', services: { service: { status: 'HEALTHY', debug: { foo: 'bar' } } } }; ``` ### With Debugging Disabled If debugging is disabled (or not explicitly enabled), the output will omit the debug details, providing a cleaner result. ```ts await medicus.performCheck(); const result = { status: 'HEALTHY', services: {} }; ``` --- --- url: 'https://medicus.js.org/error-logger.md' --- # Error Logger Medicus provides robust support for managing errors during health checks. Whether the error occurs in an **automatic background check** or during a **manual check**, you can configure a custom `errorLogger` function to centralize and customize error handling for your system. ## Custom Error Logger The `errorLogger` is a configurable function that receives the error and the name of the checker where it occurred. This makes it easy to integrate your logging solution and ensure consistent error tracking. ```ts import { Medicus } from 'medicus'; const medicus = new Medicus({ // Custom error handling implementation errorLogger(error, checkerName) { console.log('Health check failed:', checkerName, error); } }); ``` ## Default Error Logger If no custom error logger is provided, Medicus uses a default implementation based on `console.error`. This is straightforward and sufficient for development environments but can be replaced with a more robust solution for production. ```ts import { MedicusErrorLogger } from 'medicus'; export const defaultErrorLogger: MedicusErrorLogger = ( error, checkerName ) => { console.error(`Health check failed for ${checkerName}`, error); }; ``` ## Integrations ### Pino Medicus supports integration with [Pino](./integrations/pino.md), a high-performance JSON logger, allowing you to easily use Pino as your error logger. ## Custom Integrations Do you need to integrate another logging tool or a custom solution? Medicus is designed to be flexible, letting you add your own error logger with ease. Have a great implementation you'd like to share? [Contribute to Medicus](https://github.com/arthurfiorette/medicus/pulls) by opening a pull request! --- --- url: 'https://medicus.js.org/integrations/fastify.md' --- # Fastify Fastify is a high-performance web framework for Node.js, designed to offer an exceptional developer experience with minimal overhead and a robust plugin architecture. You can integrate Medicus with your Fastify application by attaching it to your instance's lifecycle hooks using the `fastifyMedicusPlugin`: ```ts import fastify from 'fastify'; import { fastifyMedicusPlugin } from 'medicus/fastify'; import { nodeMedicusPlugin } from 'medicus/node'; const app = fastify(); // Register Medicus plugin app.register(fastifyMedicusPlugin, { plugins: [nodeMedicusPlugin()] }); // The health check route is automatically set up app.listen({ port: 3000 }); ``` Once registered, the health check route will be available at `http://localhost:3000/health`. Additionally, the `app.medicus` object is exposed, allowing you to interact directly with the Medicus instance for custom health check logic. For more details about Fastify, visit the [Fastify documentation](https://www.fastify.io/). --- --- url: 'https://medicus.js.org/get-started.md' --- # Get Started Implementing health checks and collecting their output is straightforward, but **Medicus** elevates this process to a new level. Medicus offers more than just simplicity; it delivers an extensive ecosystem of **ready-to-use integrations**, **comprehensive documentation**, and **native compatibility** with popular libraries and frameworks. By providing pre-built checks, clear guidance for setup, and seamless support for your preferred stack, Medicus makes health monitoring effortless yet highly effective. It enables developers to focus on building their applications, confident that system health is being managed with minimal effort and maximum reliability. ## Installation Install Medicus using your preferred package manager: ::: code-group ```sh [npm] npm install medicus ``` ```sh [pnpm] pnpm install medicus ``` ```sh [yarn] yarn add medicus ``` ::: ## Health Result A health check is only as valuable as the clarity and usefulness of its output. Medicus ensures that the health results it provides are well-structured and easy to integrate with any monitoring or observability system. ### Example Output Here’s an example of the JSON result returned by Medicus: ```jsonc { // Overall application status "status": "degraded", // Service-specific health statuses "services": { "serviceA": { "status": "healthy" }, "serviceB": { "status": "degraded" }, // Example from the Node.js integration "node": { "status": "healthy", // Debug information, available on demand "debug": { "ts": 1733244812638, "uptime": 505236.41, "platform": "linux", "arch": "x64", "cpus": 20, "cpuUsageSystem": 21416, "cpuUsageUser": 299829, "memoryTotal": 29429706752, "memoryFree": 4879138816, "loadAverage1m": 0.64, "loadAverage5m": 0.73, "loadAverage15m": 0.83 } } } } ``` ### Key Features * **Top-Level Status:**\ The `status` field summarizes the overall health of the application as `healthy`, `degraded`, or `unhealthy`. * **Service-Specific Statuses:**\ Each service or component is listed under `services` with its individual status. * **Optional Debug Information:**\ The `debug` section provides detailed metrics for authenticated or diagnostic use cases. This feature is configurable, allowing you to control access to sensitive system details such as CPU usage, memory stats, and load averages. This structured result format makes it straightforward to monitor application health, pinpoint degraded services, and integrate with tools like Prometheus, Grafana, or custom dashboards. ## Medicus Class The `Medicus` class is the core of the library. While you’ll often use Medicus through one of its [integrations](./integrations/index.md), it’s helpful to understand its base functionality. A `Medicus` instance allows you to define and manage health checkers for your application. ```ts import { Medicus, HealthStatus, type MedicusOption } from 'medicus'; const medicus = new Medicus({ checkers: { postgresDatabase() { // Run some checks return HealthStatus.HEALTHY; } } }); // Add or remove checkers dynamically medicus.removeChecker('postgresDatabase'); // true medicus.addChecker({ redisDatabase() { // Run some checks return HealthStatus.UNHEALTHY; } }); ``` ## Context Health checks often require a connection to your application’s state or resources. This is where the `context` feature comes in. When initializing a `Medicus` instance, you can pass a `context` object that will be provided to all health checkers when they execute. ```ts import { Medicus, HealthStatus } from 'medicus'; const medicus = new Medicus({ context: { dbConnection: 'postgres://localhost:5432' } }); medicus.addChecker({ database(context) { // Typed context! console.log(context.dbConnection); return HealthStatus.HEALTHY; } }); ``` The `context` ensures that your health checkers have access to the resources and data they need, simplifying setup and ensuring consistency. --- --- url: 'https://medicus.js.org/integrations.md' --- # Integrations `Medicus` offers two types of integrations, each designed to extend its functionality in unique ways. ## Plugins Plugins are used within `Medicus`'s `plugins` configuration option to enhance its capabilities for specific integrations: * **[Pino](./pino.md):** Integrates with the `Pino` logger to map error logging effectively. * **[Node.js](./node.md):** Adds a `Node.js` health checker to monitor event loop lag and ensure runtime stability. ## Third-Party Integrations These integrations allow you to seamlessly connect `Medicus` with external libraries and frameworks: * **[Avvio](./avvio.md):** Hooks `Medicus` into the `Avvio` lifecycle to initiate health checks after the server is ready. * **[Fastify](./fastify.md):** Attaches `Medicus` to `Fastify` instance lifecycle hooks for streamlined integration. --- --- url: 'https://medicus.js.org/integrations/node.md' --- # Node The `nodeMedicusPlugin` is a plugin that adds a health check for the Node process, with optional system diagnostics. It provides detailed system information, such as CPU usage, memory stats, load averages, and uptime when the `debug` flag is enabled (which is set to `true` by default). To integrate the `nodeMedicusPlugin` into your Medicus setup, simply import and register it with your Medicus instance: ```ts import { Medicus } from 'medicus'; import { nodeMedicusPlugin } from 'medicus/node'; const medicus = new Medicus({ plugins: [nodeMedicusPlugin()] }); ``` ## Options The `nodeMedicusPlugin` accepts the following options: * **`checkerName`**: The name of the checker. Defaults to `node`. * **`debug`**: Controls if this plugin should show detailed system information on a debug health request. Defaults to `true`. Users might wanna disable this in case showing this kind of detailed information is not needed on debug requests. ## Output When the `debug` flag is enabled, the plugin will return detailed system information when the health check is called. ```jsonc { "status": "HEALTHY", "debug": { "ts": 1637590109385, // Timestamp of the health check "uptime": 12567, // System uptime in seconds "platform": "linux", // Operating system platform "arch": "x64", // System architecture "cpus": 8, // Number of CPUs "cpuUsageSystem": 1536000, // System CPU usage in microseconds "cpuUsageUser": 1200000, // User CPU usage in microseconds "memoryTotal": 17179869184, // Total system memory in bytes "memoryFree": 8589934592, // Free system memory in bytes "loadAverage1m": 1.25, // Load average for the last 1 minute "loadAverage5m": 1.35, // Load average for the last 5 minutes "loadAverage15m": 1.22 // Load average for the last 15 minutes } } ``` When the `debug` flag is disabled, the plugin will return just a health status without additional system diagnostics. ```json { "status": "healthy" } ``` --- --- url: 'https://medicus.js.org/guides/non-exposed-services.md' --- # Non exposed services TODO --- --- url: 'https://medicus.js.org/integrations/pino.md' --- # Pino Pino is a fast and lightweight JSON logger designed for both development and production environments. It offers structured logging with advanced features for enhanced debugging and monitoring. The `pinoMedicusPlugin` allows you to integrate Pino into `Medicus`, replacing its default error logger with Pino's powerful logging capabilities. ```ts import { Medicus } from 'medicus'; import { pinoMedicusPlugin } from 'medicus/pino'; import { pino } from 'pino'; const pinoInstance = pino(); // Configure Medicus to use Pino for error logging const medicus = new Medicus({ plugins: [pinoMedicusPlugin(pinoInstance)] }); ``` This integration ensures that all errors and diagnostic logs produced by `Medicus` are formatted and processed using Pino's structured logging. For additional details, visit the [Pino documentation](https://getpino.io). --- --- url: 'https://medicus.js.org/plugins.md' --- # Plugins Plugins in `Medicus` serve as the primary mechanism to customize and extend its functionality. They enable integration with third-party services or the addition of new features tailored to your application's requirements. ## Creating Plugins To create a plugin, define its structure using the `definePlugin` function. A plugin can introduce new health checkers, modify configuration options, or respond to lifecycle events. ```ts import { definePlugin, HealthStatus } from 'medicus'; export const myPlugin = definePlugin(() => ({ // Add new health checkers checkers: { myCheck() { return HealthStatus.HEALTHY; } }, // Modify default configuration or introduce new options configure(options) { options.backgroundCheckInterval = 30; }, // Hook into the instance creation lifecycle created(medicus) { console.log( `Medicus instance created with ${medicus.countCheckers()} checkers!` ); } })); ``` ## Customizing Plugin Options Plugins can be made configurable by defining options in their structure. This allows dynamic behavior based on the options provided during initialization. ```ts import { definePlugin, HealthStatus } from 'medicus'; export const myPlugin = definePlugin<{ fail: boolean }>((options) => { if (options.fail) { throw new Error('Plugin failed'); } return { checkers: { myCheck() { return HealthStatus.HEALTHY; } } }; }); ``` ## Plugin Context Sometimes, plugins require additional contextual values. You can define a context type using a generic argument for `definePlugin`. This ensures the context is correctly passed and validated. ```ts // @errors: 2322 import { definePlugin, Medicus, HealthStatus } from 'medicus'; // Define a plugin expecting context of type `{ a: string }` export const myPlugin = definePlugin(() => ({ /* Plugin implementation */ })); // Valid usage: context matches plugin expectations const valid = new Medicus<{ a: string }>({ context: { a: 'Arthur' }, plugins: [myPlugin()] }); // Invalid usage: context mismatch const invalid = new Medicus<{ b: string }>({ context: { b: 'Arthur' }, plugins: [myPlugin()] }); ``` With plugins, your creativity is the limit. They provide a flexible and powerful way to extend `Medicus` while maintaining clear and organized code. --- --- url: 'https://medicus.js.org/guides/sql-databases.md' --- # SQL Databases TODO --- --- url: 'https://medicus.js.org/guides/redis.md' --- # SQL Databases TODO --- --- url: 'https://medicus.js.org/index.md' ---