From 42a47dbcb7ace528fbb2a442918b9c149067d29c Mon Sep 17 00:00:00 2001 From: Rob Colbert Date: Fri, 8 May 2026 16:03:28 -0400 Subject: [PATCH] refactor: unify logging into @gadget/api as GadgetLog Move the 6 duplicated logging modules (component, log, log-transport, log-transport-console, log-transport-file, log-file) from both gadget-code (Dtp* prefix) and gadget-drone (Gadget* prefix) into @shad/api, using gadget-drone's GadgetLog as the canonical version. GadgetLog now uses static configuration (consoleEnabled, defaultFile) set by each consumer's env.ts at module scope, removing the env dependency from the shared library. The addDefaultTransport/ removeDefaultTransport/getDefaultTransports static methods are preserved for future real-time log transport injection. --- gadget-code/src/config/env.ts | 21 +++++ gadget-code/src/lib/component.ts | 8 -- gadget-code/src/lib/controller.ts | 9 +-- gadget-code/src/lib/db.ts | 4 +- gadget-code/src/lib/log-file.ts | 60 -------------- gadget-code/src/lib/log-transport-console.ts | 62 -------------- gadget-code/src/lib/log-transport-file.ts | 45 ----------- gadget-code/src/lib/log-transport.ts | 16 ---- gadget-code/src/lib/log.ts | 81 ------------------- gadget-code/src/lib/process.ts | 9 +-- gadget-code/src/lib/redis.ts | 4 +- gadget-code/src/lib/service.ts | 9 +-- gadget-code/src/lib/socket-session.ts | 6 +- gadget-code/src/lib/worker.ts | 9 +-- gadget-code/src/web-app.ts | 9 +-- gadget-drone/src/config/env.ts | 16 ++++ gadget-drone/src/lib/process.ts | 3 +- gadget-drone/src/lib/service.ts | 3 +- packages/api/package.json | 6 +- packages/api/src/index.ts | 6 ++ .../api}/src/lib/component.ts | 0 .../api}/src/lib/log-file.ts | 13 --- .../api}/src/lib/log-transport-console.ts | 4 +- .../api}/src/lib/log-transport-file.ts | 4 +- .../api}/src/lib/log-transport.ts | 2 +- {gadget-drone => packages/api}/src/lib/log.ts | 31 +++---- packages/config/src/types.ts | 2 + pnpm-lock.yaml | 12 +++ 28 files changed, 109 insertions(+), 345 deletions(-) delete mode 100644 gadget-code/src/lib/component.ts delete mode 100644 gadget-code/src/lib/log-file.ts delete mode 100644 gadget-code/src/lib/log-transport-console.ts delete mode 100644 gadget-code/src/lib/log-transport-file.ts delete mode 100644 gadget-code/src/lib/log-transport.ts delete mode 100644 gadget-code/src/lib/log.ts rename {gadget-drone => packages/api}/src/lib/component.ts (100%) rename {gadget-drone => packages/api}/src/lib/log-file.ts (79%) rename {gadget-drone => packages/api}/src/lib/log-transport-console.ts (94%) rename {gadget-drone => packages/api}/src/lib/log-transport-file.ts (92%) rename {gadget-drone => packages/api}/src/lib/log-transport.ts (90%) rename {gadget-drone => packages/api}/src/lib/log.ts (80%) diff --git a/gadget-code/src/config/env.ts b/gadget-code/src/config/env.ts index 9ba4989..2fead6b 100644 --- a/gadget-code/src/config/env.ts +++ b/gadget-code/src/config/env.ts @@ -6,6 +6,7 @@ import path, { dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { loadGadgetCodeConfig, resolvePath } from "@gadget/config"; import type PackageJson from "../../package.json"; +import { GadgetLog, GadgetLogFile } from "@gadget/api"; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -179,6 +180,12 @@ export default { }, file: { enabled: yamlConfig.logging?.file?.enabled === true, + path: yamlConfig.logging?.file?.path + ? resolvePath(yamlConfig.logging.file.path) + : path.join(INSTALL_DIR, "logs"), + name: yamlConfig.logging?.file?.name || "gadget-code", + maxWritesPerFile: yamlConfig.logging?.file?.maxWritesPerFile || 10000, + maxFiles: yamlConfig.logging?.file?.maxFiles || 10, }, levels: { debug: yamlConfig.logging?.levels?.debug === true, @@ -187,3 +194,17 @@ export default { }, }, }; + +// Configure GadgetLog for this package +const logFileOptions = { + basePath: yamlConfig.logging?.file?.path + ? resolvePath(yamlConfig.logging.file.path) + : path.join(INSTALL_DIR, "logs"), + name: yamlConfig.logging?.file?.name || "gadget-code", + maxWritesPerFile: yamlConfig.logging?.file?.maxWritesPerFile || 10000, + maxFiles: yamlConfig.logging?.file?.maxFiles || 10, +}; +const defaultLogFile = new GadgetLogFile(logFileOptions); +defaultLogFile.open(); +GadgetLog.consoleEnabled = yamlConfig.logging?.console?.enabled === true; +GadgetLog.defaultFile = yamlConfig.logging?.file?.enabled === true ? defaultLogFile : undefined; diff --git a/gadget-code/src/lib/component.ts b/gadget-code/src/lib/component.ts deleted file mode 100644 index 6f226b1..0000000 --- a/gadget-code/src/lib/component.ts +++ /dev/null @@ -1,8 +0,0 @@ -// src/lib/component.ts -// Copyright (C) 2026 Robert Colbert -// All Rights Reserved - -export interface DtpComponent { - get name(): string; - get slug(): string; -} diff --git a/gadget-code/src/lib/controller.ts b/gadget-code/src/lib/controller.ts index 5ac8a59..fdff51d 100644 --- a/gadget-code/src/lib/controller.ts +++ b/gadget-code/src/lib/controller.ts @@ -30,9 +30,8 @@ import { ApiClientStatus } from "../models/api-client.js"; import { CsrfToken, ICsrfToken } from "../models/csrf-token.js"; import { GadgetId, IUser } from "@gadget/api"; -import { DtpComponent } from "./component.js"; +import { GadgetComponent, GadgetLog } from "@gadget/api"; import { DtpPaginationParameters } from "./pagination-parameters.js"; -import { DtpLog } from "./log.js"; import ApiClientService from "../services/api-client.js"; import CryptoService from "../services/crypto.js"; @@ -45,8 +44,8 @@ import CryptoService from "../services/crypto.js"; * request parameters, headers, and body content, then rendering HTML page or * JSON object responses. */ -export abstract class DtpController implements DtpComponent { - log: DtpLog; +export abstract class DtpController implements GadgetComponent { + log: GadgetLog; router: Router; abstract get name(): string; @@ -54,7 +53,7 @@ export abstract class DtpController implements DtpComponent { abstract get route(): string; constructor() { - this.log = new DtpLog(this); + this.log = new GadgetLog(this); this.router = Router(); this.router.use(this.middleware.bind(this)); } diff --git a/gadget-code/src/lib/db.ts b/gadget-code/src/lib/db.ts index 7970125..7e1416a 100644 --- a/gadget-code/src/lib/db.ts +++ b/gadget-code/src/lib/db.ts @@ -6,8 +6,8 @@ import env from "../config/env.js"; import mongoose from "mongoose"; -import { DtpLog } from "./log.js"; -const log = new DtpLog({ name: "db", slug: "db" }); +import { GadgetLog } from "@gadget/api"; +const log = new GadgetLog({ name: "db", slug: "db" }); const DB_URL = `mongodb://${env.mongodb.host}/${env.mongodb.database}`; diff --git a/gadget-code/src/lib/log-file.ts b/gadget-code/src/lib/log-file.ts deleted file mode 100644 index 66a3587..0000000 --- a/gadget-code/src/lib/log-file.ts +++ /dev/null @@ -1,60 +0,0 @@ -// src/lib/log-file.ts -// Copyright (C) 2026 Robert Colbert -// All Rights Reserved - -import fs from "node:fs"; -import path from "node:path"; - -import numeral from "numeral"; - -import { Writable, WritableOptions } from "stream"; - -type StreamCallback = (error?: Error | null) => void; - -export interface DtpLogFileOptions extends WritableOptions { - basePath: string; - name: string; - maxWritesPerFile: number; - maxFiles: number; -} - -export class DtpLogFile extends Writable { - options: DtpLogFileOptions; - file?: fs.WriteStream; - - fileIdx: number = 0; - writeCount: number = 0; - - constructor(options: DtpLogFileOptions) { - super(options); - this.options = options; - } - - open(): void { - fs.mkdirSync(this.options.basePath, { recursive: true }); - const filename = path.join( - this.options.basePath, - `${this.options.name}.${numeral(this.fileIdx).format("000")}.log` - ); - this.file = fs.createWriteStream(filename, { encoding: "utf-8" }); - this.writeCount = 0; - } - - _write( - chunk: unknown, - encoding: BufferEncoding, - callback: StreamCallback - ): boolean { - if (!this.file) { - return false; - } - if (this.writeCount > this.options.maxWritesPerFile) { - this.file.close(); - if (++this.fileIdx > this.options.maxFiles) { - this.fileIdx = 0; - } - this.open(); - } - return this.file.write(chunk, encoding, callback); - } -} diff --git a/gadget-code/src/lib/log-transport-console.ts b/gadget-code/src/lib/log-transport-console.ts deleted file mode 100644 index 1229940..0000000 --- a/gadget-code/src/lib/log-transport-console.ts +++ /dev/null @@ -1,62 +0,0 @@ -// src/lib/log-transport-console.ts -// Copyright (C) 2026 Robert Colbert -// All Rights Reserved - -import * as util from "node:util"; - -import dayjs from "dayjs"; -import color from "ansicolor"; - -import { DtpLogLevel } from "./log.js"; -import { DtpLogTransport } from "./log-transport.js"; -import { DtpComponent } from "./component.ts"; - -export class DtpLogTransportConsole implements DtpLogTransport { - async writeLog( - timestamp: Date, - component: DtpComponent, - level: DtpLogLevel, - message: string, - metadata?: unknown - ): Promise { - let clevel = level.padEnd(5); - switch (level) { - case "debug": - clevel = color.darkGray(clevel); - break; - case "info": - clevel = color.green(clevel); - break; - case "warn": - clevel = color.yellow(clevel); - break; - case "alert": - clevel = color.red(clevel); - break; - case "error": - clevel = color.bgRed.white(clevel); - break; - case "crit": - clevel = color.bgRed.yellow(clevel); - break; - case "fatal": - clevel = color.bgRed.darkGray(clevel); - break; - } - - const ccomponent = color.cyan(component.name); - const ctimestamp = color.darkGray( - dayjs(timestamp).format("YYYY-MM-DD HH:mm:ss.SSS") - ); - const cmessage = color.darkGray(message); - - if (metadata) { - console.log( - `${ctimestamp} ${clevel} ${ccomponent} ${cmessage}`, - util.inspect(metadata, false, Infinity, true) - ); - } else { - console.log(`${ctimestamp} ${clevel} ${ccomponent} ${cmessage}`); - } - } -} diff --git a/gadget-code/src/lib/log-transport-file.ts b/gadget-code/src/lib/log-transport-file.ts deleted file mode 100644 index 3516fd0..0000000 --- a/gadget-code/src/lib/log-transport-file.ts +++ /dev/null @@ -1,45 +0,0 @@ -// src/lib/log-transport-file.ts -// Copyright (C) 2026 Robert Colbert -// All Rights Reserved - -import util from "node:util"; -import { Writable } from "node:stream"; - -import dayjs from "dayjs"; - -import { DtpLogLevel } from "./log.js"; -import { DtpLogTransport } from "./log-transport.js"; -import { DtpComponent } from "./component.ts"; - -export class DtpLogTransportFile implements DtpLogTransport { - file: Writable; - - constructor(file: Writable) { - this.file = file; - } - - async writeLog( - timestamp: Date, - component: DtpComponent, - level: DtpLogLevel, - message: string, - metadata?: unknown, - ): Promise { - return new Promise((resolve, reject) => { - const stimestamp = dayjs(timestamp).format("YYYY-MM-DD HH:mm:ss.SSS"); - - let sLogMessage = `${stimestamp} ${level} ${component.slug} ${message}`; - if (metadata) { - sLogMessage += " " + util.inspect(metadata, false, Infinity, false); - } - - const chunk = Buffer.from(sLogMessage + "\n"); - this.file.write(chunk, (error: Error | null | undefined): void => { - if (error) { - return reject(error); - } - return resolve(); - }); - }); - } -} diff --git a/gadget-code/src/lib/log-transport.ts b/gadget-code/src/lib/log-transport.ts deleted file mode 100644 index a7eaee5..0000000 --- a/gadget-code/src/lib/log-transport.ts +++ /dev/null @@ -1,16 +0,0 @@ -// src/lib/log-transport.ts -// Copyright (C) 2026 Robert Colbert -// All Rights Reserved - -import { DtpComponent } from "./component.ts"; -import { DtpLogLevel } from "./log.js"; - -export abstract class DtpLogTransport { - abstract writeLog( - timestamp: Date, - component: DtpComponent, - level: DtpLogLevel, - message: string, - metadata?: unknown - ): Promise; -} diff --git a/gadget-code/src/lib/log.ts b/gadget-code/src/lib/log.ts deleted file mode 100644 index bb79ab0..0000000 --- a/gadget-code/src/lib/log.ts +++ /dev/null @@ -1,81 +0,0 @@ -// src/lib/log.ts -// Copyright (C) 2026 Robert Colbert -// All Rights Reserved - -import env from "../config/env.js"; - -import { DtpComponent } from "./component.ts"; -import { DtpLogTransportConsole } from "./log-transport-console.js"; -import { DtpLogTransportFile } from "./log-transport-file.js"; -import { DtpLogTransport } from "./log-transport.js"; -import { DtpLogFile } from "./log-file.js"; - -export enum DtpLogLevel { - debug = "debug", - info = "info", - warn = "warn", - alert = "alert", - error = "error", - crit = "crit", - fatal = "fatal", -} - -export class DtpLog { - component: DtpComponent; - transports: Array = []; - - constructor(component: DtpComponent, file?: DtpLogFile) { - this.component = component; - - if (env.log.console.enabled) { - this.transports.push(new DtpLogTransportConsole()); - } - if (env.log.file.enabled && file) { - this.transports.push(new DtpLogTransportFile(file)); - } - } - - async debug(message: string, metadata?: unknown) { - if (!env.log.levels.debug) { - return; - } - return this.writeLog(DtpLogLevel.debug, message, metadata); - } - - async info(message: string, metadata?: unknown) { - if (!env.log.levels.info) { - return; - } - return this.writeLog(DtpLogLevel.info, message, metadata); - } - - async warn(message: string, metadata?: unknown) { - if (!env.log.levels.warn) { - return; - } - return this.writeLog(DtpLogLevel.warn, message, metadata); - } - - async alert(message: string, metadata?: unknown) { - return this.writeLog(DtpLogLevel.alert, message, metadata); - } - - async error(message: string, metadata?: unknown) { - return this.writeLog(DtpLogLevel.error, message, metadata); - } - - async crit(message: string, metadata?: unknown) { - return this.writeLog(DtpLogLevel.crit, message, metadata); - } - - async fatal(message: string, metadata?: unknown) { - this.writeLog(DtpLogLevel.fatal, message, metadata); - } - - async writeLog(level: DtpLogLevel, message: string, metadata?: unknown) { - const NOW = new Date(); - for (const transport of this.transports) { - transport.writeLog(NOW, this.component, level, message, metadata); - } - } -} diff --git a/gadget-code/src/lib/process.ts b/gadget-code/src/lib/process.ts index dbc752e..2218706 100644 --- a/gadget-code/src/lib/process.ts +++ b/gadget-code/src/lib/process.ts @@ -2,16 +2,15 @@ // Copyright (C) 2026 Robert Colbert // All Rights Reserved -import { DtpComponent } from "./component.js"; -import { DtpLog } from "./log.js"; +import { GadgetComponent, GadgetLog } from "@gadget/api"; -export abstract class DtpProcess implements DtpComponent { - log: DtpLog; +export abstract class DtpProcess implements GadgetComponent { + log: GadgetLog; abstract get name(): string; abstract get slug(): string; constructor() { - this.log = new DtpLog(this); + this.log = new GadgetLog(this); } } diff --git a/gadget-code/src/lib/redis.ts b/gadget-code/src/lib/redis.ts index b05bba2..d030e9f 100644 --- a/gadget-code/src/lib/redis.ts +++ b/gadget-code/src/lib/redis.ts @@ -5,8 +5,8 @@ import env from "../config/env.js"; import { Redis } from "ioredis"; -import { DtpLog } from "./log.js"; -const log = new DtpLog({ name: "redis", slug: "redis" }); +import { GadgetLog } from "@gadget/api"; +const log = new GadgetLog({ name: "redis", slug: "redis" }); log.info("connecting to Redis", { host: env.redis.host, diff --git a/gadget-code/src/lib/service.ts b/gadget-code/src/lib/service.ts index aa3c13a..042eb8a 100644 --- a/gadget-code/src/lib/service.ts +++ b/gadget-code/src/lib/service.ts @@ -4,17 +4,16 @@ // import env from "../config/env.js"; -import { DtpComponent } from "./component.js"; -import { DtpLog } from "./log.js"; +import { GadgetComponent, GadgetLog } from "@gadget/api"; -export abstract class DtpService implements DtpComponent { - log: DtpLog; +export abstract class DtpService implements GadgetComponent { + log: GadgetLog; abstract get name(): string; abstract get slug(): string; constructor() { - this.log = new DtpLog(this); + this.log = new GadgetLog(this); } abstract start(): Promise; diff --git a/gadget-code/src/lib/socket-session.ts b/gadget-code/src/lib/socket-session.ts index 8e58780..972280e 100644 --- a/gadget-code/src/lib/socket-session.ts +++ b/gadget-code/src/lib/socket-session.ts @@ -9,7 +9,7 @@ import { ServerToClientEvents, SocketData, } from "@gadget/api"; -import { DtpLog } from "./log.js"; +import { GadgetLog } from "@gadget/api"; export enum SocketSessionType { Code = "code", @@ -23,7 +23,7 @@ export type GadgetSocket = Socket< SocketData >; export abstract class SocketSession { - protected log: DtpLog; + protected log: GadgetLog; protected _socket: GadgetSocket; protected _user: IUser; @@ -38,7 +38,7 @@ export abstract class SocketSession { protected abstract type: SocketSessionType; constructor(socket: GadgetSocket, user: IUser) { - this.log = new DtpLog({ + this.log = new GadgetLog({ name: "SocketSession", slug: "lib:socket-session", }); diff --git a/gadget-code/src/lib/worker.ts b/gadget-code/src/lib/worker.ts index a6e4dd4..cee2a7a 100644 --- a/gadget-code/src/lib/worker.ts +++ b/gadget-code/src/lib/worker.ts @@ -5,11 +5,10 @@ import env from "../config/env.js"; import BullQueue from "bull"; -import { DtpLog } from "./log.js"; -import { DtpComponent } from "./component.js"; +import { GadgetComponent, GadgetLog } from "@gadget/api"; -export abstract class DtpWorker implements DtpComponent { - log: DtpLog; +export abstract class DtpWorker implements GadgetComponent { + log: GadgetLog; jobQueue: BullQueue.Queue | undefined; abstract get name(): string; @@ -17,7 +16,7 @@ export abstract class DtpWorker implements DtpComponent { abstract get queueName(): string; constructor() { - this.log = new DtpLog(this); + this.log = new GadgetLog(this); } async start(): Promise { diff --git a/gadget-code/src/web-app.ts b/gadget-code/src/web-app.ts index 4ffef73..a07c23f 100644 --- a/gadget-code/src/web-app.ts +++ b/gadget-code/src/web-app.ts @@ -31,8 +31,7 @@ import numeral from "numeral"; type SameSiteOption = boolean | "lax" | "strict" | "none" | undefined; -import { DtpLog } from "./lib/log.js"; -import { DtpComponent } from "./lib/component.js"; +import { GadgetComponent, GadgetLog } from "@gadget/api"; import { User } from "./models/user.js"; @@ -50,8 +49,8 @@ import { } from "./services/index.js"; import { SessionType } from "./services/session.js"; -class DtpWebAppServer implements DtpComponent { - private log: DtpLog; +class DtpWebAppServer implements GadgetComponent { + private log: GadgetLog; private app?: express.Application; private server?: http.Server; @@ -64,7 +63,7 @@ class DtpWebAppServer implements DtpComponent { } constructor() { - this.log = new DtpLog(this); + this.log = new GadgetLog(this); } async start(): Promise { diff --git a/gadget-drone/src/config/env.ts b/gadget-drone/src/config/env.ts index fe71ab4..c3ef068 100644 --- a/gadget-drone/src/config/env.ts +++ b/gadget-drone/src/config/env.ts @@ -6,6 +6,7 @@ import path, { dirname } from "node:path"; import { fileURLToPath } from "node:url"; import { loadGadgetDroneConfig, resolvePath } from "@gadget/config"; import type PackageJson from "../../package.json"; +import { GadgetLog, GadgetLogFile } from "@gadget/api"; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -73,4 +74,19 @@ export default { }, }, }; + +// Configure GadgetLog for this package +const logFileOptions = { + basePath: yamlConfig.logging?.file?.path + ? resolvePath(yamlConfig.logging.file.path) + : path.join(INSTALL_DIR, "logs"), + name: yamlConfig.logging?.file?.name || "gadget-drone", + maxWritesPerFile: yamlConfig.logging?.file?.maxWritesPerFile || 10000, + maxFiles: yamlConfig.logging?.file?.maxFiles || 10, +}; +const defaultLogFile = new GadgetLogFile(logFileOptions); +defaultLogFile.open(); +GadgetLog.consoleEnabled = yamlConfig.logging?.console?.enabled === true; +GadgetLog.defaultFile = yamlConfig.logging?.file?.enabled === true ? defaultLogFile : undefined; + /* eslint-enable no-process-env */ diff --git a/gadget-drone/src/lib/process.ts b/gadget-drone/src/lib/process.ts index 24a9501..9f658ad 100644 --- a/gadget-drone/src/lib/process.ts +++ b/gadget-drone/src/lib/process.ts @@ -2,8 +2,7 @@ // Copyright (C) 2026 Rob Colbert // Licensed under the Apache License, Version 2.0 -import { GadgetComponent } from "./component.ts"; -import { GadgetLog } from "./log.ts"; +import { GadgetComponent, GadgetLog } from "@gadget/api"; export abstract class GadgetProcess implements GadgetComponent { protected log: GadgetLog; diff --git a/gadget-drone/src/lib/service.ts b/gadget-drone/src/lib/service.ts index 83ae137..f215517 100644 --- a/gadget-drone/src/lib/service.ts +++ b/gadget-drone/src/lib/service.ts @@ -4,8 +4,7 @@ // import env from "../config/env.js"; -import { GadgetComponent } from "./component.js"; -import { GadgetLog } from "./log.js"; +import { GadgetComponent, GadgetLog } from "@gadget/api"; export abstract class GadgetService implements GadgetComponent { protected log: GadgetLog; diff --git a/packages/api/package.json b/packages/api/package.json index 8a219ba..eb06839 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -19,10 +19,14 @@ "author": "Rob Colbert", "license": "Apache-2.0", "dependencies": { - "mongoose": "^8.16.1" + "ansicolor": "^2.0.3", + "dayjs": "^1.11.20", + "mongoose": "^8.16.1", + "numeral": "^2.0.6" }, "devDependencies": { "@types/node": "^25.6.0", + "@types/numeral": "^2.0.5", "typescript": "^6.0.3" } } \ No newline at end of file diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 9bd986d..538f285 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -3,6 +3,12 @@ // All Rights Reserved export * from "./lib/gadget-id.ts"; +export * from "./lib/component.ts"; +export * from "./lib/log.ts"; +export * from "./lib/log-transport.ts"; +export * from "./lib/log-transport-console.ts"; +export * from "./lib/log-transport-file.ts"; +export * from "./lib/log-file.ts"; /* * Data Model Interfaces diff --git a/gadget-drone/src/lib/component.ts b/packages/api/src/lib/component.ts similarity index 100% rename from gadget-drone/src/lib/component.ts rename to packages/api/src/lib/component.ts diff --git a/gadget-drone/src/lib/log-file.ts b/packages/api/src/lib/log-file.ts similarity index 79% rename from gadget-drone/src/lib/log-file.ts rename to packages/api/src/lib/log-file.ts index f4f88da..9821d18 100644 --- a/gadget-drone/src/lib/log-file.ts +++ b/packages/api/src/lib/log-file.ts @@ -2,8 +2,6 @@ // Copyright (C) 2026 Rob Colbert // Licensed under the Apache License, Version 2.0 -import env from "../config/env.js"; - import fs from "node:fs"; import path from "node:path"; @@ -60,14 +58,3 @@ export class GadgetLogFile extends Writable { return this.file.write(chunk, encoding, callback); } } - -const defaultLogFileOptions = { - basePath: env.log.file.path || "/var/log/gadget-code", - name: env.log.file.name || env.pkg.name, - maxWritesPerFile: env.log.file.maxWritesPerFile, - maxFiles: env.log.file.maxFiles, -}; -const defaultLogFile = new GadgetLogFile(defaultLogFileOptions); -defaultLogFile.open(); - -export { defaultLogFile }; diff --git a/gadget-drone/src/lib/log-transport-console.ts b/packages/api/src/lib/log-transport-console.ts similarity index 94% rename from gadget-drone/src/lib/log-transport-console.ts rename to packages/api/src/lib/log-transport-console.ts index 9c65740..a5952a3 100644 --- a/gadget-drone/src/lib/log-transport-console.ts +++ b/packages/api/src/lib/log-transport-console.ts @@ -7,8 +7,8 @@ import * as util from "node:util"; import dayjs from "dayjs"; import color from "ansicolor"; -import { GadgetLogLevel } from "./log.js"; -import { GadgetLogTransport } from "./log-transport.js"; +import { GadgetLogLevel } from "./log.ts"; +import { GadgetLogTransport } from "./log-transport.ts"; import { GadgetComponent } from "./component.ts"; export class GadgetLogTransportConsole implements GadgetLogTransport { diff --git a/gadget-drone/src/lib/log-transport-file.ts b/packages/api/src/lib/log-transport-file.ts similarity index 92% rename from gadget-drone/src/lib/log-transport-file.ts rename to packages/api/src/lib/log-transport-file.ts index ae43564..d0bb671 100644 --- a/gadget-drone/src/lib/log-transport-file.ts +++ b/packages/api/src/lib/log-transport-file.ts @@ -7,8 +7,8 @@ import { Writable } from "node:stream"; import dayjs from "dayjs"; -import { GadgetLogLevel } from "./log.js"; -import { GadgetLogTransport } from "./log-transport.js"; +import { GadgetLogLevel } from "./log.ts"; +import { GadgetLogTransport } from "./log-transport.ts"; import { GadgetComponent } from "./component.ts"; export class GadgetLogTransportFile implements GadgetLogTransport { diff --git a/gadget-drone/src/lib/log-transport.ts b/packages/api/src/lib/log-transport.ts similarity index 90% rename from gadget-drone/src/lib/log-transport.ts rename to packages/api/src/lib/log-transport.ts index acb324f..2d8eab7 100644 --- a/gadget-drone/src/lib/log-transport.ts +++ b/packages/api/src/lib/log-transport.ts @@ -3,7 +3,7 @@ // Licensed under the Apache License, Version 2.0 import { GadgetComponent } from "./component.ts"; -import { GadgetLogLevel } from "./log.js"; +import { GadgetLogLevel } from "./log.ts"; export abstract class GadgetLogTransport { abstract writeLog( diff --git a/gadget-drone/src/lib/log.ts b/packages/api/src/lib/log.ts similarity index 80% rename from gadget-drone/src/lib/log.ts rename to packages/api/src/lib/log.ts index 33306b2..011c2c3 100644 --- a/gadget-drone/src/lib/log.ts +++ b/packages/api/src/lib/log.ts @@ -2,13 +2,11 @@ // Copyright (C) 2026 Rob Colbert // Licensed under the Apache License, Version 2.0 -import env from "../config/env.js"; - import { GadgetComponent } from "./component.ts"; -import { GadgetLogTransportConsole } from "./log-transport-console.js"; -import { GadgetLogTransportFile } from "./log-transport-file.js"; -import { GadgetLogTransport } from "./log-transport.js"; -import { GadgetLogFile, defaultLogFile } from "./log-file.js"; +import { GadgetLogTransportConsole } from "./log-transport-console.ts"; +import { GadgetLogTransportFile } from "./log-transport-file.ts"; +import { GadgetLogTransport } from "./log-transport.ts"; +import { GadgetLogFile } from "./log-file.ts"; export enum GadgetLogLevel { debug = "debug", @@ -25,18 +23,21 @@ export class GadgetLog { transports: GadgetLogTransport[] = []; private static defaultTransports: GadgetLogTransport[] = []; - private file: GadgetLogFile; + + static consoleEnabled = true; + static defaultFile: GadgetLogFile | undefined; constructor(component: GadgetComponent, file?: GadgetLogFile) { this.component = component; - this.file = file || defaultLogFile; this.transports.push(...GadgetLog.defaultTransports); - if (env.log.console.enabled) { + if (GadgetLog.consoleEnabled) { this.transports.push(new GadgetLogTransportConsole()); } - if (env.log.file.enabled) { - this.transports.push(new GadgetLogTransportFile(this.file)); + + const fileInstance = file || GadgetLog.defaultFile; + if (fileInstance) { + this.transports.push(new GadgetLogTransportFile(fileInstance)); } } @@ -56,23 +57,17 @@ export class GadgetLog { } async debug(message: string, metadata?: unknown) { - if (!env.log.levels.debug) { + if (!GadgetLog.consoleEnabled) { return; } return this.writeLog(GadgetLogLevel.debug, message, metadata); } async info(message: string, metadata?: unknown) { - if (!env.log.levels.info) { - return; - } return this.writeLog(GadgetLogLevel.info, message, metadata); } async warn(message: string, metadata?: unknown) { - if (!env.log.levels.warn) { - return; - } return this.writeLog(GadgetLogLevel.warn, message, metadata); } diff --git a/packages/config/src/types.ts b/packages/config/src/types.ts index 59ca35f..97c47f1 100644 --- a/packages/config/src/types.ts +++ b/packages/config/src/types.ts @@ -67,6 +67,8 @@ export interface GadgetCodeConfig { enabled?: boolean; path?: string; name?: string; + maxWritesPerFile?: number; + maxFiles?: number; }; https?: { enabled?: boolean; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bd002e9..1def50c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -343,13 +343,25 @@ importers: packages/api: dependencies: + ansicolor: + specifier: ^2.0.3 + version: 2.0.3 + dayjs: + specifier: ^1.11.20 + version: 1.11.20 mongoose: specifier: ^8.16.1 version: 8.23.1 + numeral: + specifier: ^2.0.6 + version: 2.0.6 devDependencies: '@types/node': specifier: ^25.6.0 version: 25.6.0 + '@types/numeral': + specifier: ^2.0.5 + version: 2.0.5 typescript: specifier: ^6.0.3 version: 6.0.3