How LoggerService Interfaces with the Cordis Context: Deep Implementation Guide

The LoggerService binds to the Cordis execution context through constructor injection, effect-based lifecycle management, and fiber-aware message emission, enabling scoped logging that automatically cleans up when contexts dispose.

The LoggerService in the cordiverse/cordis repository provides a sophisticated logging layer that leverages the framework's context system for dependency injection, configuration resolution, and execution tracking. Understanding how this service interfaces with the Cordis context reveals the architectural patterns that make the framework modular and reactive.

Constructor Injection and Context Storage

The LoggerService establishes its relationship with the Cordis context immediately upon instantiation. In packages/core/src/logger.ts at lines 79–84, the service receives a Context instance through its constructor and stores it in the ctx property (lines 73–87). This context binding makes the service aware of its execution scope from the moment it is created.

Storing the context reference allows the logger to access framework-level services, configuration intercepts, and the current execution fiber throughout its lifecycle. This pattern ensures that every logger instance operates within a specific contextual boundary rather than existing as a global singleton.

Effect-Based Lifecycle Management

After securing the context reference, the service registers its cleanup logic through the context's effect system. At lines 89–102 in packages/core/src/logger.ts, the constructor invokes ctx.effect to register default exporters. This effect registration ties the logger's resource lifecycle directly to the context's disposal mechanism.

When the Cordis context is torn down, the effect system automatically triggers cleanup for all registered logger exporters. This prevents memory leaks and ensures that file handles, network connections, or other resources held by transport layers are released precisely when their parent context terminates.

Dynamic Configuration via Context Intercepts

The LoggerService resolves configuration dynamically through the context's intercept system. When invoked via the [symbols.invoke] method at lines 126–138, the service reads configuration overrides from ctx[symbols.intercept] (lines 140–144). This mechanism enables per-context configuration such as default log levels, logger names, and formatter options.

Framework users can inject configuration at any point in the context hierarchy:

import { LoggerLevel } from 'cordis'

// Override defaults for this context and its children
ctx.intercept({
  logger: { 
    level: LoggerLevel.WARN, 
    name: 'custom-logger' 
  },
})

// Subsequent logger instances respect the intercept
const logger = ctx.logger()
logger.debug('Filtered out')  // Ignored due to WARN level
logger.warn('Visible log')    // Emitted successfully

The service merges these intercepted values with instance-specific parameters, allowing granular control over logging behavior across different application layers.

Fiber-Aware Message Emission

Every log message generated through the LoggerService maintains a reference to its execution context via the Cordis fiber system. When creating a logger instance, the service accesses the current fiber through (caller ?? this.ctx).fiber at lines 145–146. If no explicit name is provided, it falls back to the fiber's hyphenated representation (lines 149–150).

During message emission (lines 162–166), the service iterates over registered exporters and determines the effective log level by evaluating the exporter's level map, the logger's configured level, and the default level (lines 163–165). Each constructed Message object includes a WeakRef to the current fiber at lines 168–169, enabling downstream consumers to correlate log entries with specific execution paths without preventing garbage collection.

This fiber association allows debugging tools to trace logs back to their originating contextual fibers, even in complex asynchronous scenarios involving multiple nested contexts.

Summary

  • Constructor binding: LoggerService stores the Cordis Context instance in its ctx property during instantiation (lines 73–87).
  • Automated cleanup: The service registers exporters through ctx.effect, ensuring resources release when contexts dispose (lines 89–102).
  • Configurable intercepts: Configuration overrides are read from ctx[symbols.intercept], enabling per-context log levels and names (lines 140–144).
  • Execution tracking: Log messages capture the current fiber via (caller ?? this.ctx).fiber, binding entries to their execution context (lines 145–150, 168–169).

Frequently Asked Questions

How does LoggerService access the current execution fiber?

The service retrieves the active fiber through the expression (caller ?? this.ctx).fiber at lines 145–146 in packages/core/src/logger.ts. If an explicit caller context is provided during logger creation, it uses that context's fiber; otherwise, it falls back to the service's own context fiber. This ensures every logger instance remains associated with its correct execution scope.

Can I override logger configuration for specific contexts?

Yes. The framework supports context intercepts that allow you to override logger configuration at any level of the context tree. By calling ctx.intercept({ logger: { level, name } }), you modify the default behavior for all subsequent ctx.logger() calls within that scope. The service reads these values via ctx[symbols.intercept] at lines 140–144.

What happens to logger exporters when a context is disposed?

The exporters are automatically cleaned up. During construction at lines 89–102, LoggerService registers its exporter initialization logic through ctx.effect(). When the Cordis context triggers its disposal sequence, the effect system invokes the cleanup functions, releasing all associated transport resources without manual intervention.

Where is the LoggerService defined in the source code?

The primary implementation resides in packages/core/src/logger.ts. Supporting infrastructure exists in packages/core/src/context.ts (effect system and intercept handling), packages/core/src/fiber.ts (execution fiber tracking), and packages/core/src/utils.ts (symbols and helper utilities like createCallable that enable the service's callable interface).

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →