/**
* MIT License
*
* Copyright (c) 2025 Chris M. Perez
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/* eslint-disable no-console */
import { Effect } from 'effect';
import { TracingService } from './TracingService.js';
import type { AnyResolvedLayer } from '../types.js';
export const withLayerSpan = (
layer: AnyResolvedLayer,
effect: Effect.Effect
): Effect.Effect =>
Effect.gen(function* () {
const tracing = yield* TracingService;
if (!tracing.isEnabled()) {
return yield* effect;
}
const attributes: Record = {
layer: layer.name,
};
if (
layer.dependencies &&
(layer.dependencies as readonly string[]).length > 0
) {
attributes['depends'] = layer.dependencies;
}
if (layer.provides) {
const provides = Object.keys(layer.provides);
if (provides.length > 0) {
attributes['provides'] = provides;
}
}
const start = performance.now();
tracing.startSpan(`Layer: ${layer.name}`, attributes);
try {
const result = yield* effect;
const duration = performance.now() - start;
tracing.logSpan(`Layer: ${layer.name}`, duration, attributes, 1);
return result;
} finally {
tracing.endSpan(`Layer: ${layer.name}`);
}
});
export const withRuntimeSpan = (
effect: Effect.Effect,
layerCount: number
): Effect.Effect =>
Effect.gen(function* () {
const tracing = yield* TracingService;
if (!tracing.isEnabled()) {
return yield* effect;
}
const start = performance.now();
tracing.startSpan('LayerRuntime.init', { layers: layerCount });
try {
const result = yield* effect;
const duration = performance.now() - start;
tracing.logSpan('LayerRuntime.init', duration, { layers: layerCount }, 0);
return result;
} finally {
tracing.endSpan('LayerRuntime.init');
}
});
export const logDependencyGraph = (
layers: readonly AnyResolvedLayer[]
): Effect.Effect =>
Effect.gen(function* () {
const tracing = yield* TracingService;
if (!tracing.isEnabled() || !tracing.config.verbose) {
return;
}
const styles = {
label: 'color: gray; font-weight: lighter;',
name: 'color: inherit; font-weight: bold;',
time: 'color: gray; font-weight: lighter;',
layer: 'color: #03A9F4; font-weight: bold;',
deps: 'color: #9E9E9E;',
};
const time = new Date().toLocaleTimeString();
console.groupCollapsed(
`%clayers %c${String(layers.length)} registered %c@ ${time}`,
styles.label,
styles.name,
styles.time
);
for (const layer of layers) {
const deps =
layer.dependencies &&
(layer.dependencies as readonly string[]).length > 0
? ` <- [${(layer.dependencies as string[]).join(', ')}]`
: '';
console.log(`%c${layer.name}%c${deps}`, styles.layer, styles.deps);
}
console.groupEnd();
});